File Coverage

blib/lib/DBIx/DBO/Row.pm
Criterion Covered Total %
statement 188 200 94.0
branch 80 100 80.0
condition 47 81 58.0
subroutine 34 35 97.1
pod 14 14 100.0
total 363 430 84.4


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