File Coverage

blib/lib/DBIx/DBO/Row.pm
Criterion Covered Total %
statement 197 218 90.3
branch 82 108 75.9
condition 30 71 42.2
subroutine 34 35 97.1
pod 13 13 100.0
total 356 445 80.0


line stmt bran cond sub pod time code
1             package DBIx::DBO::Row;
2              
3 11     11   60 use strict;
  11         21  
  11         416  
4 11     11   59 use warnings;
  11         20  
  11         382  
5 11     11   52 use Carp 'croak';
  11         21  
  11         827  
6 11     11   59 use Scalar::Util qw(blessed weaken);
  11         22  
  11         505  
7 11     11   12191 use Storable ();
  11         43487  
  11         910  
8              
9 11 100   11   97 use overload '@{}' => sub {${$_[0]}->{array} || []}, '%{}' => sub {${$_[0]}->{hash}}, fallback => 1;
  11     19   20  
  11         163  
  19         40  
  19         166  
  60         116  
  60         285  
10              
11 3     3   7 sub _table_class { ${$_[0]}->{DBO}->_table_class }
  3         20  
12              
13             *_isa = \&DBIx::DBO::DBD::_isa;
14              
15             =head1 NAME
16              
17             DBIx::DBO::Row - An OO interface to SQL queries and results. Encapsulates a fetched row of data in an object.
18              
19             =head1 SYNOPSIS
20              
21             # Create a Row object for the `users` table
22             my $row = $dbo->row('users');
23            
24             # Load my record
25             $row->load(login => 'vlyon') or die "Where am I?";
26            
27             # Double my salary :)
28             $row->update(salary => {FUNC => '? * 2', COL => 'salary'});
29            
30             # Print my email address
31             print $row->{email};
32            
33             # Delete my boss
34             $row->load(id => $row->{boss_id})->delete or die "Can't kill the boss";
35              
36             =head1 METHODS
37              
38             =head3 C
39              
40             DBIx::DBO::Row->new($dbo, $table);
41             DBIx::DBO::Row->new($dbo, $query_object);
42              
43             Create and return a new C object.
44             The object returned represents rows in the given table/query.
45             Can take the same arguments as L or a L object can be used.
46              
47             =cut
48              
49             sub new {
50 25     25 1 1524 my $proto = shift;
51 25 100       39 eval { $_[0]->isa('DBIx::DBO') } or croak 'Invalid DBO Object for new Row';
  25         168  
52 24   66     123 my $class = ref($proto) || $proto;
53 24         101 $class->_init(@_);
54             }
55              
56             sub _init {
57 24     24   52 my($class, $dbo, $parent) = @_;
58 24 100       67 croak 'Missing parent for new Row' unless defined $parent;
59              
60 23         200 my $me = bless \{ DBO => $dbo, array => undef, hash => {} }, $class;
61 23 100       136 $parent = $me->_table_class->new($dbo, $parent) unless blessed $parent;
62              
63 23         480 $$me->{build_data}{LimitOffset} = [1];
64 23 100       175 if ($parent->isa('DBIx::DBO::Query')) {
    100          
65 13 100       51 croak 'This query is from a different DBO connection' if $parent->{DBO} != $dbo;
66 12         36 $$me->{Parent} = $parent;
67             # We must weaken this to avoid a circular reference
68 12         58 weaken $$me->{Parent};
69 12         75 $parent->columns;
70 12         16 $$me->{Tables} = [ @{$parent->{Tables}} ];
  12         42  
71 12         35 $$me->{Columns} = $parent->{Columns};
72 12         58 $$me->{build_data}{from} = $dbo->{dbd_class}->_build_from($parent);
73 12         50 $me->_copy_build_data;
74             } elsif ($parent->isa('DBIx::DBO::Table')) {
75 9 100       41 croak 'This table is from a different DBO connection' if $parent->{DBO} != $dbo;
76 8         45 $$me->{build_data} = {
77             show => '*',
78             Showing => [],
79             from => $parent->_from,
80             group => '',
81             order => '',
82             };
83 8         269 $$me->{Tables} = [ $parent ];
84 8         29 $$me->{Columns} = $parent->{Columns};
85             } else {
86 1         3 croak 'Invalid parent for new Row';
87             }
88 20 100       186 return wantarray ? ($me, $me->tables) : $me;
89             }
90              
91             sub _copy_build_data {
92 31     31   59 my $me = $_[0];
93             # Store needed build_data
94 31         64 for my $f (qw(Showing From_Bind Quick_Where Where_Data Where_Bind group Group_Bind order Order_Bind)) {
95 279 100       1237 $$me->{build_data}{$f} = $me->_copy($$me->{Parent}{build_data}{$f}) if exists $$me->{Parent}{build_data}{$f};
96             }
97             }
98              
99             sub _copy {
100 1106     1106   1589 my($me, $val) = @_;
101 1106 100 100     2210 return bless [$me, $val->[1]], 'DBIx::DBO::Column'
102             if _isa($val, 'DBIx::DBO::Column') and $val->[0] == $$me->{Parent};
103 1104 100       5067 ref $val eq 'ARRAY' ? [map $me->_copy($_), @$val] : ref $val eq 'HASH' ? {map $me->_copy($_), %$val} : $val;
    100          
104             }
105              
106             sub _build_data {
107 127     127   1501 ${$_[0]}->{build_data};
  127         433  
108             }
109              
110             =head3 C
111              
112             Return a list of L objects for this row.
113              
114             =cut
115              
116             sub tables {
117 24     24 1 32 @{${$_[0]}->{Tables}};
  24         29  
  24         91  
118             }
119              
120             sub _table_idx {
121 33     33   56 my($me, $tbl) = @_;
122 33         44 for my $i (0 .. $#{$$me->{Tables}}) {
  33         101  
123 36 100       155 return $i if $tbl == $$me->{Tables}[$i];
124             }
125 0         0 return;
126             }
127              
128             sub _table_alias {
129 35     35   52 my($me, $tbl) = @_;
130 35 100       110 return undef if $tbl == $me;
131 33         74 my $i = $me->_table_idx($tbl);
132 33 50       88 croak 'The table is not in this query' unless defined $i;
133 33 100       39 @{$$me->{Tables}} > 1 ? 't'.($i + 1) : ();
  33         201  
134             }
135              
136             =head3 C
137              
138             Return a list of column names.
139              
140             =cut
141              
142             sub columns {
143 13     13 1 26 my($me) = @_;
144              
145 13 100       57 return $$me->{Parent}->columns if $$me->{Parent};
146              
147 0         0 @{$$me->{Columns}} = do {
  12         49  
148 0 0       0 if (@{$$me->{build_data}{Showing}}) {
  0         0  
149 0 0       0 map {
150 0         0 _isa($_, 'DBIx::DBO::Table', 'DBIx::DBO::Query') ? ($_->columns) : $me->_build_col_val_name(@$_)
151 0         0 } @{$$me->{build_data}{Showing}};
152             } else {
153 0         0 map { $_->columns } @{$$me->{Tables}};
  0         0  
  0         0  
154             }
155 12 50       21 } unless @{$$me->{Columns}};
156              
157 12         34 @{$$me->{Columns}};
  12         53  
158             }
159              
160             *_build_col_val_name = \&DBIx::DBO::Query::_build_col_val_name;
161              
162             sub _column_idx {
163 20     20   32 my($me, $col) = @_;
164 20         29 my $idx = -1;
165 20 100       26 for my $shown (@{$$me->{build_data}{Showing}} ? @{$$me->{build_data}{Showing}} : @{$$me->{Tables}}) {
  20         67  
  5         14  
  15         31  
166 25 100       68 if (_isa($shown, 'DBIx::DBO::Table')) {
167 21 100 66     140 if ($col->[0] == $shown and exists $shown->{Column_Idx}{$col->[1]}) {
168 19         88 return $idx + $shown->{Column_Idx}{$col->[1]};
169             }
170 2         3 $idx += keys %{$shown->{Column_Idx}};
  2         6  
171 2         4 next;
172             }
173 4         7 $idx++;
174 4 100 66     17 return $idx if not defined $shown->[1] and @{$shown->[0]} == 1 and $col == $shown->[0][0];
  2   100     16  
175             }
176 0         0 return;
177             }
178              
179             =head3 C
180              
181             $row->column($column_name);
182              
183             Returns a column reference from the name or alias.
184              
185             =cut
186              
187             sub column {
188 1     1 1 553 my($me, $col) = @_;
189 1         3 my @show;
190 1 50       2 @show = @{$$me->{build_data}{Showing}} or @show = @{$$me->{Tables}};
  1         3  
  1         8  
191 1         4 for my $fld (@show) {
192             return $$me->{Column}{$col} ||= bless [$me, $col], 'DBIx::DBO::Column'
193             if (_isa($fld, 'DBIx::DBO::Table') and exists $fld->{Column_Idx}{$col})
194 1 0 0     5 or (_isa($fld, 'DBIx::DBO::Query') and eval { $fld->column($col) })
  0   33     0  
      33        
      33        
      33        
      33        
      33        
195             or (ref($fld) eq 'ARRAY' and exists $fld->[2]{AS} and $col eq $fld->[2]{AS});
196             }
197 1         7 croak 'No such column: '.$$me->{DBO}{dbd_class}->_qi($me, $col);
198             }
199              
200             sub _inner_col {
201 15     15   35 my($me, $col, $_check_aliases) = @_;
202 15 50       42 $_check_aliases = $$me->{DBO}{dbd_class}->_alias_preference($me, 'column') unless defined $_check_aliases;
203 15         26 my $column;
204 15 50 33     45 return $column if $_check_aliases == 1 and $column = $me->_check_alias($col);
205 15         45 for my $tbl ($me->tables) {
206 15 50       104 return $tbl->column($col) if exists $tbl->{Column_Idx}{$col};
207             }
208 0 0 0     0 return $column if $_check_aliases == 2 and $column = $me->_check_alias($col);
209 0 0       0 croak 'No such column'.($_check_aliases ? '/alias' : '').': '.$$me->{DBO}{dbd_class}->_qi($me, $col);
210             }
211              
212             sub _check_alias {
213 0     0   0 my($me, $col) = @_;
214 0         0 for my $fld (@{$$me->{build_data}{Showing}}) {
  0         0  
215 0 0 0     0 return $$me->{Column}{$col} ||= bless [$me, $col], 'DBIx::DBO::Column'
      0        
      0        
216             if ref($fld) eq 'ARRAY' and exists $fld->[2]{AS} and $col eq $fld->[2]{AS};
217             }
218             }
219              
220             =head3 C
221              
222             $value = $row->value($column);
223              
224             Return the value in the C<$column> field.
225             C<$column> can be a column name or a C object.
226              
227             Values in the C can also be obtained by using the object as an array/hash reference.
228              
229             $value = $row->[2];
230             $value = $row->{some_column};
231              
232             =cut
233              
234             sub value {
235 7     7 1 21 my($me, $col) = @_;
236 7 100       30 croak 'The row is empty' unless $$me->{array};
237 6 100       16 if (_isa($col, 'DBIx::DBO::Column')) {
238 4         17 my $i = $me->_column_idx($col);
239 4 50       32 return $$me->{array}[$i] if defined $i;
240 0         0 croak 'The field '.$$me->{DBO}{dbd_class}->_qi($me, $col->[0]{Name}, $col->[1]).' was not included in this query';
241             }
242 2 100       13 return $$me->{hash}{$col} if exists $$me->{hash}{$col};
243 1         7 croak 'No such column: '.$$me->{DBO}{dbd_class}->_qi($me, $col);
244             }
245              
246             =head3 C
247              
248             $row->load(id => 123);
249             $row->load(name => 'Bob', status => 'Employed');
250              
251             Fetch a new row using the where definition specified.
252             Returns the C object if the row is found and loaded successfully.
253             Returns an empty list if there is no row or an error occurs.
254              
255             =cut
256              
257             sub load {
258 10     10 1 30 my $me = shift;
259              
260 10         43 $me->_detach;
261              
262             # Use Quick_Where to load a row, but make sure to restore its value afterward
263 10         14 my $old_qw = $#{$$me->{build_data}{Quick_Where}};
  10         43  
264 10         21 push @{$$me->{build_data}{Quick_Where}}, @_;
  10         36  
265 10         36 undef $$me->{build_data}{where};
266 10         74 my $sql = $$me->{DBO}{dbd_class}->_build_sql_select($me);
267 10         74 my @bind = $$me->{DBO}{dbd_class}->_bind_params_select($me);
268 10 50       67 $old_qw < 0 ? delete $$me->{build_data}{Quick_Where} : ($#{$$me->{build_data}{Quick_Where}} = $old_qw);
  0         0  
269 10         29 delete $$me->{build_data}{where};
270 10         27 delete $$me->{build_data}{Where_Bind};
271              
272 10         39 return $me->_load($sql, @bind);
273             }
274              
275             sub _load {
276 11     11   29 my($me, $sql, @bind) = @_;
277 11         26 undef $$me->{array};
278 11         36 $$me->{hash} = \my %hash;
279 11         90 $$me->{DBO}{dbd_class}->_sql($me, $sql, @bind);
280 11         32 my $sth = $me->rdbh->prepare($sql);
281 11 50 33     1895 return unless $sth and $sth->execute(@bind);
282              
283 11         92 my $i;
284             my @array;
285 11         42 for ($me->columns) {
286 27         155 $i++;
287 27 100       207 $sth->bind_col($i, \$hash{$_}) unless exists $hash{$_};
288             }
289 11 100       150 $$me->{array} = $sth->fetch or return;
290 10         118 $sth->finish;
291 10         203 $me;
292             }
293              
294             sub _detach {
295 11     11   24 my $me = $_[0];
296 11 100       46 if (exists $$me->{Parent}) {
297 4         7 $$me->{Columns} = [ @{$$me->{Columns}} ];
  4         21  
298 4         31 $$me->{array} = [ @$me ];
299 4         13 $$me->{hash} = { %$me };
300 4         14 undef $$me->{Parent}{Row};
301             # Save config from Parent
302 4 100 66     36 if ($$me->{Parent}{Config} and %{$$me->{Parent}{Config}}) {
  4         32  
303 3 100       7 $$me->{Config} = { %{$$me->{Parent}{Config}}, $$me->{Config} ? %{$$me->{Config}} : () };
  3         21  
  1         6  
304             }
305             }
306 11         35 delete $$me->{Parent};
307             }
308              
309             =head3 C
310              
311             $row->update(id => 123);
312             $row->update(name => 'Bob', status => 'Employed');
313              
314             Updates the current row with the new values specified.
315             Returns the number of rows updated or C<'0E0'> for no rows to ensure the value is true,
316             and returns false if there was an error.
317              
318             Note: If C is supported on Cs then only the first matching row will be updated
319             otherwise ALL rows matching the current row will be updated.
320              
321             =cut
322              
323             sub update {
324 5     5 1 520 my $me = shift;
325 5 100       120 croak "Can't update an empty row" unless $$me->{array};
326 4         33 my @update = $$me->{DBO}{dbd_class}->_parse_set($me, @_);
327 4         28 local $$me->{build_data} = $$me->{DBO}{dbd_class}->_build_data_matching_this_row($me);
328 4 50 33     14 $$me->{build_data}{LimitOffset} = ($me->config('LimitRowUpdate') and $me->tables == 1) ? [1] : undef;
329 4         28 my $sql = $$me->{DBO}{dbd_class}->_build_sql_update($me, @update);
330              
331 4         26 my $rv = $$me->{DBO}{dbd_class}->_do($me, $sql, undef, $$me->{DBO}{dbd_class}->_bind_params_update($me));
332 4 50 33     1095 $$me->{DBO}{dbd_class}->_reset_row_on_update($me, @update) if $rv and $rv > 0;
333 4         42 return $rv;
334             }
335              
336             =head3 C
337              
338             $row->delete;
339              
340             Deletes the current row.
341             Returns the number of rows deleted or C<'0E0'> for no rows to ensure the value is true,
342             and returns false if there was an error.
343             The C object will then be empty.
344              
345             Note: If C is supported on Cs then only the first matching row will be deleted
346             otherwise ALL rows matching the current row will be deleted.
347              
348             =cut
349              
350             sub delete {
351 2     2 1 569 my $me = shift;
352 2 100       14 croak "Can't delete an empty row" unless $$me->{array};
353 1         8 local $$me->{build_data} = $$me->{DBO}{dbd_class}->_build_data_matching_this_row($me);
354 1 50 33     4 $$me->{build_data}{LimitOffset} = ($me->config('LimitRowDelete') and $me->tables == 1) ? [1] : undef;
355 1         15 my $sql = $$me->{DBO}{dbd_class}->_build_sql_delete($me, @_);
356              
357 1         3 undef $$me->{array};
358 1         4 $$me->{hash} = {};
359 1         15 $$me->{DBO}{dbd_class}->_do($me, $sql, undef, $$me->{DBO}{dbd_class}->_bind_params_delete($me));
360             }
361              
362             =head3 C
363              
364             return $row->{id} unless $row->is_empty;
365              
366             Checks to see if it's an empty C, and returns true or false.
367              
368             =cut
369              
370             sub is_empty {
371 2     2 1 9 my $me = shift;
372 2         14 return not defined $$me->{array};
373             }
374              
375             =head2 Common Methods
376              
377             These methods are accessible from all DBIx::DBO* objects.
378              
379             =head3 C
380              
381             The C object.
382              
383             =head3 C
384              
385             The I C handle.
386              
387             =head3 C
388              
389             The I C handle, or if there is no I connection, the I C handle.
390              
391             =cut
392              
393 5     5 1 25 sub dbo { ${$_[0]}->{DBO} }
  5         28  
394 5     5 1 9 sub dbh { ${$_[0]}->{DBO}->dbh }
  5         29  
395 51     51 1 62 sub rdbh { ${$_[0]}->{DBO}->rdbh }
  51         232  
396              
397             =head3 C
398              
399             $row_setting = $row->config($option);
400             $row->config($option => $row_setting);
401              
402             Get or set the C config settings. When setting an option, the previous value is returned. When getting an option's value, if the value is undefined, the C object (If the the C belongs to one) or L's value is returned.
403              
404             See L.
405              
406             =cut
407              
408             sub config {
409 101     101 1 136 my $me = shift;
410 101         129 my $opt = shift;
411 101 100 100     356 return $$me->{DBO}{dbd_class}->_set_config($$me->{Config} ||= {}, $opt, shift) if @_;
412 82 100 100     632 $$me->{DBO}{dbd_class}->_get_config($opt, $$me->{Config} ||= {}, defined $$me->{Parent} ? ($$me->{Parent}{Config}) : (), $$me->{DBO}{Config}, \%DBIx::DBO::Config);
413             }
414              
415             *STORABLE_freeze = sub {
416 4     4   129 my($me, $cloning) = @_;
417 4 100       120 return unless exists $$me->{Parent};
418              
419             # Simulate detached row
420 1         1 local $$me->{Columns} = [ @{$$me->{Columns}} ];
  1         5  
421             # Save config from Parent
422 1         3 my $parent = delete $$me->{Parent};
423 1         7 local $$me->{Config} = { %{$parent->{Config}}, $$me->{Config} ? %{$$me->{Config}} : () }
  0         0  
  1         7  
424 1 50 33     6 if $parent->{Config} and %{$parent->{Config}};
    50          
425              
426 1         4 my $frozen = Storable::nfreeze($me);
427 1         10 $$me->{Parent} = $parent;
428 1         34 return $frozen;
429             } if $Storable::VERSION >= 2.38;
430              
431             *STORABLE_thaw = sub {
432 1     1   413 my($me, $cloning, @frozen) = @_;
433 1         2 $$me = { %${ Storable::thaw(@frozen) } }; # Copy the hash, or Storable will wipe it out!
  1         4  
434             } if $Storable::VERSION >= 2.38;
435              
436             sub DESTROY {
437 24     24   30611 undef %${$_[0]};
  24         582  
438             }
439              
440             1;
441              
442             __END__