File Coverage

blib/lib/Jifty/DBI/SchemaGenerator.pm
Criterion Covered Total %
statement 21 65 32.3
branch 0 16 0.0
condition 0 3 0.0
subroutine 7 13 53.8
pod 4 4 100.0
total 32 101 31.6


line stmt bran cond sub pod time code
1 1     1   109493 use strict;
  1         1  
  1         25  
2 1     1   3 use warnings;
  1         1  
  1         36  
3              
4             package Jifty::DBI::SchemaGenerator;
5              
6 1     1   2 use base qw(Class::Accessor::Fast);
  1         2  
  1         441  
7 1     1   2810 use DBIx::DBSchema;
  1         1  
  1         19  
8 1     1   4 use DBIx::DBSchema::Column;
  1         2  
  1         13  
9 1     1   3 use DBIx::DBSchema::Table;
  1         1  
  1         14  
10 1     1   388 use Class::ReturnValue;
  1         10672  
  1         634  
11              
12             our $VERSION = '0.01';
13              
14             # Public accessors
15             __PACKAGE__->mk_accessors(qw(handle));
16              
17             # Internal accessors: do not use from outside class
18             __PACKAGE__->mk_accessors(qw(_db_schema));
19              
20             =head1 NAME
21              
22             Jifty::DBI::SchemaGenerator - Generate table schemas from Jifty::DBI records
23              
24             =head1 DESCRIPTION
25              
26             This module turns a Jifty::Record object into an SQL schema for your chosen
27             database. At the moment, your choices are MySQL, SQLite, or PostgreSQL.
28             Oracle might also work right, though it's untested.
29              
30             =head1 SYNOPSIS
31              
32             =head2 The Short Answer
33              
34             See below for where we get the $handle and $model variables.
35              
36             use Jifty::DBI::SchemaGenerator;
37             ...
38             my $s_gen = Jifty::DBI::SchemaGenerator->new( $handle );
39             $s_gen->add_model($model);
40              
41             my @statements = $s_gen->create_table_sql_statements;
42             print join("\n", @statements, '');
43             ...
44              
45             =head2 The Long Version
46              
47             See L<Jifty::DBI> for details about the first two parts.
48              
49             =over
50              
51             =item MyModel
52              
53             package MyModel;
54             # lib/MyModel.pm
55              
56             use warnings;
57             use strict;
58              
59             use base qw(Jifty::DBI::Record);
60             # your custom code goes here.
61             1;
62              
63             =item MyModel::Schema
64              
65             package MyModel::Schema;
66             # lib/MyModel/Schema.pm
67              
68             use warnings;
69             use strict;
70              
71             use Jifty::DBI::Schema;
72              
73             column foo => type is 'text';
74             column bar => type is 'text';
75              
76             1;
77              
78             =item myscript.pl
79              
80             #!/usr/bin/env perl
81             # myscript.pl
82              
83             use strict;
84             use warnings;
85              
86             use Jifty::DBI::SchemaGenerator;
87              
88             use Jifty::DBI::Handle;
89             use MyModel;
90             use MyModel::Schema;
91              
92             my $handle = Jifty::DBI::Handle->new();
93             $handle->connect(
94             driver => 'SQLite',
95             database => 'testdb',
96             );
97              
98             my $model = MyModel->new($handle);
99             my $s_gen = Jifty::DBI::SchemaGenerator->new( $handle );
100             $s_gen->add_model($model);
101              
102             # here's the basic point of this module:
103             my @statements = $s_gen->create_table_sql_statements;
104             print join("\n", @statements, '');
105              
106             # this part is directly from Jifty::Script::Schema::create_all_tables()
107             $handle->begin_transaction;
108             for my $statement (@statements) {
109             my $ret = $handle->simple_query($statement);
110             $ret or die "error creating a table: " . $ret->error_message;
111             }
112             $handle->commit;
113              
114             =back
115              
116             =head1 CONFIGURATION AND ENVIRONMENT
117              
118             Requires no configuration files or environment variables.
119              
120              
121             =head1 DEPENDENCIES
122              
123             Class::Accessor::Fast
124              
125             DBIx::DBSchema
126              
127             Class::ReturnValue
128              
129             =head1 METHODS
130              
131             =head2 new HANDLE
132              
133             Creates a new C<Jifty::DBI::SchemaGenerator> object. The single
134             required argument is a C<Jifty::DBI::Handle>.
135              
136             =cut
137              
138             sub new {
139 0     0 1   my $class = shift;
140 0           my $handle = shift;
141 0           my $self = $class->SUPER::new();
142              
143 0           $self->handle($handle);
144              
145 0           my $schema = DBIx::DBSchema->new();
146 0           $self->_db_schema($schema);
147              
148 0           return $self;
149             }
150              
151             =head2 add_model MODEL
152              
153             Adds a new model class to the SchemaGenerator. Model should be an
154             object which is an instance of C<Jifty::DBI::Record> or a subclass
155             thereof. It may also be a string which is the name of such a
156             class/subclass; in the latter case, C<add_model> will instantiate an
157             object of the class.
158              
159             The model must define the instance methods C<Schema> and C<Table>.
160              
161             Returns true if the model was added successfully; returns a false
162             C<Class::ReturnValue> error otherwise.
163              
164             =cut
165              
166             sub add_model {
167 0     0 1   my $self = shift;
168 0           my $model = shift;
169              
170             # $model could either be a (presumably unfilled) object of a subclass of
171             # Jifty::DBI::Record, or it could be the name of such a subclass.
172              
173 0 0 0       unless ( ref $model and UNIVERSAL::isa( $model, 'Jifty::DBI::Record' ) ) {
174 0           my $new_model;
175 0           eval { $new_model = $model->new; };
  0            
176              
177 0 0         if ($@) {
178 0           return $self->_error("Error making new object from $model: $@");
179             }
180              
181 0 0         unless ( UNIVERSAL::isa( $new_model, 'Jifty::DBI::Record' ) ) {
182 0           return $self->_error(
183             "Didn't get a Jifty::DBI::Record from $model, got $new_model"
184             );
185             }
186 0           $model = $new_model;
187             }
188              
189 0           my $table_obj = $self->_db_schema_table_from_model($model);
190              
191 0           $self->_db_schema->addtable($table_obj);
192              
193 0           1;
194             }
195              
196             =head2 create_table_sql_statements
197              
198             Returns a list of SQL statements (as strings) to create tables for all of
199             the models added to the SchemaGenerator.
200              
201             =cut
202              
203             sub create_table_sql_statements {
204 0     0 1   my $self = shift;
205              
206 0           return $self->_db_schema->sql( $self->handle->dbh );
207             }
208              
209             =head2 create_table_sql_text
210              
211             Returns a string containing a sequence of SQL statements to create tables for all of
212             the models added to the SchemaGenerator.
213              
214              
215             =cut
216              
217             sub create_table_sql_text {
218 0     0 1   my $self = shift;
219              
220 0           return join "\n", map {"$_ ;\n"} $self->create_table_sql_statements;
  0            
221             }
222              
223             =head2 PRIVATE _db_schema_table_from_model MODEL
224              
225             Takes an object of a subclass of Jifty::DBI::Record; returns a new
226             C<DBIx::DBSchema::Table> object corresponding to the model.
227              
228             =cut
229              
230             sub _db_schema_table_from_model {
231 0     0     my $self = shift;
232 0           my $model = shift;
233              
234 0           my $table_name = $model->table;
235 0           my @columns = $model->columns;
236              
237 0           my @cols;
238             my @indexes;
239              
240 0           for my $column (@columns) {
241              
242             # Skip "Virtual" columns - (foreign keys to collections)
243 0 0         next if $column->virtual;
244 0 0         next if defined $column->alias_for_column;
245              
246 0 0         push @cols,
247             DBIx::DBSchema::Column->new(
248             { name => $column->name,
249             type => $column->type,
250             null => $column->mandatory ? 0 : 1,
251             default => $column->default,
252             }
253             );
254              
255 0 0         if ($column->indexed) {
256 0           push @indexes,[$column->name];
257             }
258             }
259              
260 0 0         my $table = DBIx::DBSchema::Table->new(
261             { name => $table_name,
262             primary_key => "id",
263             columns => \@cols,
264             (@indexes) ? (index => DBIx::DBSchema::ColGroup->new(\@indexes)) : ()
265             }
266             );
267              
268 0           return $table;
269             }
270              
271             =head2 PRIVATE _error STRING
272              
273             Takes in a string and returns it as a Class::ReturnValue error object.
274              
275             =cut
276              
277             sub _error {
278 0     0     my $self = shift;
279 0           my $message = shift;
280              
281 0           my $ret = Class::ReturnValue->new;
282 0           $ret->as_error( errno => 1, message => $message );
283 0           return $ret->return_value;
284             }
285              
286             1; # Magic true value required at end of module
287              
288             =head1 INCOMPATIBILITIES
289              
290             None reported.
291              
292             =head1 BUGS AND LIMITATIONS
293              
294             No bugs have been reported.
295              
296             Please report any bugs or feature requests to
297             C<bug-E<lt>RT NAMEE<gt>@rt.cpan.org>, or through the web interface at
298             L<http://rt.cpan.org>.
299              
300             =head1 AUTHOR
301              
302             David Glasser C<< glasser@bestpractical.com >>
303              
304             Some pod by Eric Wilhelm <ewilhelm at cpan dot org>
305              
306             =head1 LICENCE AND COPYRIGHT
307              
308             Copyright (c) 2005, Best Practical Solutions, LLC. All rights reserved.
309              
310             This module is free software; you can redistribute it and/or
311             modify it under the same terms as Perl itself. See L<perlartistic>.
312              
313             =head1 DISCLAIMER OF WARRANTY
314              
315             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
316             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
317             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
318             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
319             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
320             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
321             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
322             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
323             NECESSARY SERVICING, REPAIR, OR CORRECTION.
324              
325             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
326             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
327             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
328             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
329             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
330             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
331             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
332             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
333             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
334             SUCH DAMAGES.
335              
336             =cut
337