File Coverage

blib/lib/Alzabo/Runtime/RowState/Live.pm
Criterion Covered Total %
statement 12 149 8.0
branch 0 54 0.0
condition 0 6 0.0
subroutine 4 17 23.5
pod 0 9 0.0
total 16 235 6.8


line stmt bran cond sub pod time code
1             package Alzabo::Runtime::RowState::Live;
2              
3 11     11   66 use strict;
  11         21  
  11         418  
4              
5 11     11   80 use Alzabo::Exceptions;
  11         23  
  11         81  
6 11     11   61 use Alzabo::Runtime;
  11         23  
  11         237  
7 11     11   119 use Alzabo::Utils;
  11         34  
  11         36161  
8              
9             sub _where
10             {
11 0     0     my $class = shift;
12 0           my $row = shift;
13 0           my $sql = shift;
14              
15 0           my ($pk1, @pk) = $row->table->primary_key;
16              
17 0           $sql->where( $pk1, '=', $row->{pk}{ $pk1->name } );
18 0           $sql->and( $_, '=', $row->{pk}{ $_->name } ) foreach @pk;
19             }
20              
21             sub _init
22             {
23 0     0     my $class = shift;
24 0           my $row = shift;
25 0           my %p = @_;
26              
27 0           $row->{pk} = $row->_make_id_hash(%p);
28              
29 0           while ( my ($k, $v) = each %{ $row->{pk} } )
  0            
30             {
31 0           $row->{data}{$k} = $v;
32             }
33              
34 0 0         if ( $p{prefetch} )
35             {
36 0           while ( my ($k, $v) = each %{ $p{prefetch} } )
  0            
37             {
38 0           $row->{data}{$k} = $v;
39             }
40             }
41             else
42             {
43 0           eval { $class->_get_prefetch_data($row) };
  0            
44              
45 0 0         if ( my $e = $@ )
46             {
47 0 0         return if isa_alzabo_exception( $e, 'Alzabo::Exception::NoSuchRow' );
48              
49 0           rethrow_exception $e;
50             }
51             }
52              
53 0 0         unless ( keys %{ $row->{data} } > keys %{ $row->{pk} } )
  0            
  0            
54             {
55             # Need to try to fetch something to confirm that this row exists!
56 0           my $sql = ( $row->schema->sqlmaker->
57             select( ($row->table->primary_key)[0] )->
58             from( $row->table ) );
59              
60 0           $class->_where($row, $sql);
61              
62 0           $sql->debug(\*STDERR) if Alzabo::Debug::SQL;
63 0           print STDERR Devel::StackTrace->new if Alzabo::Debug::TRACE;
64              
65             return
66 0 0         unless defined $row->schema->driver->one_row( sql => $sql->sql,
67             bind => $sql->bind );
68             }
69              
70 0           return 1;
71             }
72              
73             sub _get_prefetch_data
74             {
75 0     0     my $class = shift;
76 0           my $row = shift;
77              
78 0           my @pre = $row->table->prefetch;
79              
80 0 0         return unless @pre;
81              
82 0           $class->_get_data( $row, @pre );
83             }
84              
85             sub _get_data
86             {
87 0     0     my $class = shift;
88 0           my $row = shift;
89              
90 0           my %data;
91             my @select;
92 0           foreach my $col (@_)
93             {
94 0 0         if ( exists $row->{data}{$col} )
95             {
96 0           $data{$col} = $row->{data}{$col};
97             }
98             else
99             {
100 0           push @select, $col;
101             }
102             }
103              
104 0 0         return %data unless @select;
105              
106 0           my $sql = ( $row->schema->sqlmaker->
107             select( $row->table->columns(@select) )->
108             from( $row->table ) );
109 0           $class->_where($row, $sql);
110              
111 0           $sql->debug(\*STDERR) if Alzabo::Debug::SQL;
112 0           print STDERR Devel::StackTrace->new if Alzabo::Debug::TRACE;
113              
114 0           my %d;
115 0 0         @d{@select} =
116             $row->schema->driver->one_row( sql => $sql->sql,
117             bind => $sql->bind )
118             or $row->_no_such_row_error;
119              
120 0           while ( my( $k, $v ) = each %d )
121             {
122 0           $row->{data}{$k} = $data{$k} = $v;
123             }
124              
125 0           return %data;
126             }
127              
128             sub id_as_string
129             {
130 0     0 0   my $class = shift;
131 0           my $row = shift;
132 0           my %p = @_;
133              
134 0 0         return $row->{id_string} if exists $row->{id_string};
135              
136 0           $row->{id_string} = $row->id_as_string_ext( pk => $row->{pk},
137             table => $row->table );
138 0           return $row->{id_string};
139             }
140              
141             sub select
142             {
143 0     0 0   my $class = shift;
144 0           my $row = shift;
145              
146 0 0         my @cols = @_ ? @_ : map { $_->name } $row->table->columns;
  0            
147 0           my %data = $class->_get_data( $row, @cols );
148              
149 0 0         return wantarray ? @data{@cols} : $data{ $cols[0] };
150             }
151              
152             sub select_hash
153             {
154 0     0 0   my $class = shift;
155 0           my $row = shift;
156              
157 0 0         my @cols = @_ ? @_ : map { $_->name } $row->table->columns;
  0            
158              
159 0           return $class->_get_data( $row, @cols );
160             }
161              
162             sub update
163             {
164 0     0 0   my $class = shift;
165 0           my $row = shift;
166 0           my %data = @_;
167              
168 0           my $schema = $row->schema;
169              
170 0           my @fk; # this never gets populated unless referential integrity
171             # checking is on
172             my @set;
173              
174 0           my $includes_pk = 0;
175 0           foreach my $k ( sort keys %data )
176             {
177             # This will throw an exception if the column doesn't exist.
178 0           my $c = $row->table->column($k);
179              
180 0 0         if ( $row->_cached_data_is_same( $k, $data{$k} ) )
181             {
182 0           delete $data{$k};
183 0           next;
184             }
185              
186 0 0         $includes_pk = 1 if $c->is_primary_key;
187              
188 0 0 0       Alzabo::Exception::NotNullable->throw
      0        
189             ( error => $c->name . " column in " . $row->table->name . " table cannot be null.",
190             column_name => $c->name,
191             table_name => $c->table->name,
192             schema_name => $schema->name,
193             )
194             unless defined $data{$k} || $c->nullable || defined $c->default;
195              
196 0 0         push @fk, $row->table->foreign_keys_by_column($c)
197             if $schema->referential_integrity;
198              
199 0           push @set, $c => $data{$k};
200             }
201              
202 0 0         return 0 unless keys %data;
203              
204 0           my $sql = ( $schema->sqlmaker->update( $row->table ) );
205              
206 0           $sql->set(@set);
207              
208 0           $class->_where( $row, $sql );
209              
210             # If we have foreign keys we'd like all the fiddling to be atomic.
211 0 0         $schema->begin_work if @fk;
212              
213             eval
214 0           {
215 0           foreach my $fk (@fk)
216             {
217 0           $fk->register_update( map { $_->name => $data{ $_->name } } $fk->columns_from );
  0            
218             }
219              
220 0           $sql->debug(\*STDERR) if Alzabo::Debug::SQL;
221 0           print STDERR Devel::StackTrace->new if Alzabo::Debug::TRACE;
222              
223 0           $schema->driver->do( sql => $sql->sql,
224             bind => $sql->bind );
225              
226 0 0         $schema->commit if @fk;
227             };
228              
229 0 0         if (my $e = $@)
230             {
231 0           eval { $schema->rollback };
  0            
232              
233 0           rethrow_exception $e;
234             }
235              
236 0           while ( my( $k, $v ) = each %data )
237             {
238             # These can't be stored until they're fetched from the database again
239 0 0         if ( Alzabo::Utils::safe_isa( $v, 'Alzabo::SQLMaker::Function' ) )
240             {
241 0           delete $row->{data}{$k};
242 0           next;
243             }
244              
245 0           $row->{data}{$k} = $v;
246             }
247              
248 0 0         $row->_update_pk_hash if $includes_pk;
249              
250 0           return 1;
251             }
252              
253             sub refresh
254             {
255 0     0 0   my $class = shift;
256 0           my $row = shift;
257              
258 0           delete $row->{data};
259              
260 0           $class->_get_prefetch_data($row);
261             }
262              
263             sub delete
264             {
265 0     0 0   my $class = shift;
266 0           my $row = shift;
267              
268 0           my $schema = $row->schema;
269              
270 0           my @fk;
271 0 0         if ($schema->referential_integrity)
272             {
273 0           @fk = $row->table->all_foreign_keys;
274             }
275              
276 0           my $sql = ( $schema->sqlmaker->
277             delete->from( $row->table ) );
278              
279 0           $class->_where($row, $sql);
280              
281 0 0         $schema->begin_work if @fk;
282             eval
283 0           {
284 0           foreach my $fk (@fk)
285             {
286 0           $fk->register_delete($row);
287             }
288              
289 0           $sql->debug(\*STDERR) if Alzabo::Debug::SQL;
290 0           print STDERR Devel::StackTrace->new if Alzabo::Debug::TRACE;
291              
292 0           $schema->driver->do( sql => $sql->sql,
293             bind => $sql->bind );
294              
295 0 0         $schema->commit if @fk;
296             };
297              
298 0 0         if (my $e = $@)
299             {
300 0           eval { $schema->rollback };
  0            
301              
302 0           rethrow_exception $e;
303             }
304              
305 0           $row->set_state( 'Alzabo::Runtime::RowState::Deleted' );
306             }
307              
308 0     0 0   sub is_potential { 0 }
309              
310 0     0 0   sub is_live { 1 }
311              
312 0     0 0   sub is_deleted { 0 }
313              
314              
315             1;
316              
317             __END__