File Coverage

blib/lib/Rose/DB/Object/Metadata/Auto/SQLite.pm
Criterion Covered Total %
statement 21 124 16.9
branch 0 36 0.0
condition 0 16 0.0
subroutine 7 13 53.8
pod 3 3 100.0
total 31 192 16.1


line stmt bran cond sub pod time code
1             package Rose::DB::Object::Metadata::Auto::SQLite;
2              
3 1     1   11998 use strict;
  1         3  
  1         36  
4              
5 1     1   6 use Carp();
  1         128  
  1         28  
6              
7 1     1   8 use Rose::DB::Object::Metadata::ForeignKey;
  1         2  
  1         22  
8 1     1   6 use Rose::DB::Object::Metadata::UniqueKey;
  1         3  
  1         17  
9              
10 1     1   1090 use Rose::DB::Object::Metadata::Auto;
  1         5  
  1         160  
11             our @ISA = qw(Rose::DB::Object::Metadata::Auto);
12              
13             our $VERSION = '0.784';
14              
15             sub auto_generate_columns
16             {
17 0     0 1   my($self) = shift;
18              
19 0           my($class, %columns, $error);
20              
21             TRY:
22             {
23 0           local $@;
  0            
24              
25             eval
26 0           {
27 0   0       my $col_info = ($self->_table_info)[0] || [];
28              
29 0 0         die "No columns found" unless(@$col_info);
30              
31 0           my $db = $self->db;
32 0 0         my $dbh = $db->dbh or die $db->error;
33              
34 0           foreach my $info (@$col_info)
35             {
36 0           $db->refine_dbi_column_info($info);
37              
38             $columns{$info->{'COLUMN_NAME'}} =
39 0           $self->auto_generate_column($info->{'COLUMN_NAME'}, $info);
40             }
41             };
42              
43 0           $error = $@;
44             }
45              
46 0 0 0       if($error || !keys %columns)
47             {
48 1     1   21 no warnings; # undef strings okay
  1         3  
  1         645  
49 0           Carp::croak "Could not auto-generate columns for class $class, table '",
50             $self->table, "' - $error";
51             }
52              
53 0           $self->auto_alias_columns(values %columns);
54              
55 0 0         return wantarray ? values %columns : \%columns;
56             }
57              
58             my $UK_Num = 1;
59              
60             sub auto_generate_unique_keys
61             {
62 0     0 1   my($self) = shift;
63              
64 0 0         unless(defined wantarray)
65             {
66 0           Carp::croak "Useless call to auto_generate_unique_keys() in void context";
67             }
68              
69 0           my($class, %unique_keys, $error);
70              
71             TRY:
72             {
73 0           local $@;
  0            
74              
75             eval
76 0           {
77 0   0       my $uk_info = ($self->_table_info)[2] || [];
78              
79 0           foreach my $info (@$uk_info)
80             {
81 0           my $uk_name = 'unique_key_' . $UK_Num++;
82              
83 0           my $uk = $unique_keys{$uk_name} =
84             Rose::DB::Object::Metadata::UniqueKey->new(name => $uk_name,
85             parent => $self);
86              
87 0           foreach my $column (@$info)
88             {
89 0           $uk->add_column($column);
90             }
91              
92 0           $unique_keys{$uk_name} = $uk;
93             }
94             };
95              
96 0           $error = $@;
97             }
98              
99 0 0         if($error)
100             {
101 0           Carp::croak "Could not auto-retrieve unique keys for class $class - $error";
102             }
103              
104             # This sort order is part of the API, and is essential to make the
105             # test suite work.
106 0           my @uk = map { $unique_keys{$_} } sort map { lc } keys(%unique_keys);
  0            
  0            
107              
108 0 0         return wantarray ? @uk : \@uk;
109             }
110              
111             sub auto_generate_foreign_keys
112             {
113 0     0 1   my($self, %args) = @_;
114              
115 0 0         unless(defined wantarray)
116             {
117 0           Carp::croak "Useless call to auto_generate_foreign_keys() in void context";
118             }
119              
120 0           my $no_warnings = $args{'no_warnings'};
121              
122 0           my($class, @foreign_keys, $total_fks, $error);
123              
124             TRY:
125             {
126 0           local $@;
  0            
127              
128             eval
129 0           {
130 0 0         $class = $self->class or die "Missing class!";
131              
132 0           my $db = $self->db;
133 0 0         my $dbh = $db->dbh or die $db->error;
134 0           my $table_quoted = $db->quote_table_name($self->table);
135              
136             # Silence this stupid warning when a table has no foreign keys:
137             # DBD::SQLite::st fetchrow_hashref warning: not an error(0) at dbdimp.c line 504
138 0           local $dbh->{'PrintWarn'} = 0;
139              
140 0           my $sth = $dbh->prepare("PRAGMA foreign_key_list($table_quoted)");
141 0           $sth->execute;
142              
143 0           my %fk_info;
144              
145 0           while(my $row = $sth->fetchrow_hashref)
146             {
147 0           push(@{$fk_info{$row->{'id'}}}, $row);
  0            
148             }
149              
150 0           my $cm = $self->convention_manager;
151              
152 0           FK: foreach my $id (sort { $a <=> $b } keys(%fk_info))
  0            
153             {
154 0           my $col_info = $fk_info{$id};
155              
156 0           my $foreign_table = $col_info->[0]{'table'};
157              
158 0           my $foreign_class = $self->class_for(table => $foreign_table);
159              
160 0 0         unless($foreign_class)
161             {
162             # Add deferred task
163             $self->add_deferred_task(
164             {
165             class => $self->class,
166             method => 'auto_init_foreign_keys',
167             args => \%args,
168              
169             code => sub
170             {
171 0     0     $self->auto_init_foreign_keys(%args);
172 0           $self->make_foreign_key_methods(%args, preserve_existing => 1);
173             },
174              
175             check => sub
176             {
177 0     0     my $fks = $self->foreign_keys;
178 0 0         return @$fks == $total_fks ? 1 : 0;
179             }
180 0           });
181              
182 0 0 0       unless($no_warnings || $self->allow_auto_initialization)
183             {
184 1     1   9 no warnings; # Allow undef coercion to empty string
  1         2  
  1         588  
185 0           warn "No Rose::DB::Object-derived class found for table ",
186             "'$foreign_table'";
187             }
188              
189 0           $total_fks++;
190 0           next FK;
191             }
192              
193 0           my(@local_columns, @foreign_columns);
194              
195 0           foreach my $item (@$col_info)
196             {
197 0           push(@local_columns, $item->{'from'});
198 0           push(@foreign_columns, $item->{'to'});
199             }
200              
201 0 0 0       unless(@local_columns > 0 && @local_columns == @foreign_columns)
202             {
203 0           die "Failed to extract a matched set of columns from ",
204             'PRAGMA foreign_key_list(', $self->table, ')';
205             }
206              
207 0           my %key_columns;
208 0           @key_columns{@local_columns} = @foreign_columns;
209              
210 0           my $fk =
211             Rose::DB::Object::Metadata::ForeignKey->new(
212             class => $foreign_class,
213             key_columns => \%key_columns);
214              
215 0           push(@foreign_keys, $fk);
216 0           $total_fks++;
217             }
218              
219             # This step is important! It ensures that foreign keys will be created
220             # in a deterministic order, which in turn allows the "auto-naming" of
221             # foreign keys to work in a predictable manner. This exact sort order
222             # (lowercase table name comparisons) is part of the API for foreign
223             # key auto generation.
224             @foreign_keys =
225 0           sort { lc $a->class->meta->table cmp lc $b->class->meta->table }
  0            
226             @foreign_keys;
227              
228 0           my %used_names;
229              
230 0           foreach my $fk (@foreign_keys)
231             {
232 0           my $name =
233             $cm->auto_foreign_key_name($fk->class, $fk->name, scalar $fk->key_columns, \%used_names);
234              
235 0 0         unless(defined $name)
236             {
237 0           $fk->name($name = $self->foreign_key_name_generator->($self, $fk));
238             }
239              
240 0 0 0       unless(defined $name && $name =~ /^\w+$/)
241             {
242 0           die "Missing or invalid key name '$name' for foreign key ",
243             "generated in $class for ", $fk->class;
244             }
245              
246 0           $used_names{$name}++;
247              
248 0           $fk->name($name);
249             }
250             };
251              
252 0           $error = $@;
253             }
254              
255 0 0         if($error)
256             {
257 0           Carp::croak "Could not auto-generate foreign keys for class $class - $error";
258             }
259              
260 0           @foreign_keys = sort { lc $a->name cmp lc $b->name } @foreign_keys;
  0            
261              
262 0 0         return wantarray ? @foreign_keys : \@foreign_keys;
263             }
264              
265             sub _table_info
266             {
267 0     0     my($self) = shift;
268              
269             # XXX: I'm in the process of moving all introspection to Rose::DB.
270             # XXX: _table_info is an undocumented method of Rose::DB::SQLite
271 0           $self->db->_table_info($self->table);
272             }
273              
274             1;