File Coverage

blib/lib/Teng/Row.pm
Criterion Covered Total %
statement 121 129 93.8
branch 41 48 85.4
condition 15 19 78.9
subroutine 21 21 100.0
pod 13 14 92.8
total 211 231 91.3


line stmt bran cond sub pod time code
1             use strict;
2 72     72   399 use warnings;
  72         132  
  72         1770  
3 72     72   357 use Carp ();
  72         123  
  72         1327  
4 72     72   294 our $AUTOLOAD;
  72         113  
  72         92916  
5              
6             # inside-out
7             our %obj;
8              
9             my ($class, $args) = @_;
10              
11 268     268 1 579 my $self = bless {
12             # inflated values
13 268         1765 _get_column_cached => {},
14             # values will be updated
15             _dirty_columns => {},
16             _autoload_column_cache => {},
17             %$args,
18             }, $class;
19              
20             $self->{select_columns} ||= [keys %{$args->{row_data}}];
21             $self->{table} ||= $args->{teng}->schema->get_table($args->{table_name});
22 268   100     1131  
  135         801  
23 268   100     604 $obj{$self+0} = delete $self->{teng};
24              
25 268         860 $self;
26             }
27 268         3111  
28             my ($x, $col) = @_;
29              
30             return sub {
31 780     780 0 1242 my $self = shift;
32              
33             # setter is alias of set_column (not deflate column) for historical reason
34 308     308   85224 return $self->set_column( $col => @_ ) if @_;
35              
36             # getter is alias of get (inflate column)
37 308 100       744 $self->get($col);
38             };
39             }
40 301         883  
41 780         2469  
42             my ($self, $col) = @_;
43              
44 73     73 1 342 # "Untrusted" means the row is set_column by scalarref.
45             # e.g.
46             # $row->set_column("date" => \"DATE()");
47 301     301 1 614 if ($self->{_untrusted_row_data}->{$col}) {
48             Carp::carp("${col}'s row data is untrusted. by your update query.");
49             }
50             my $cache = $self->{_get_column_cached};
51             my $data = $cache->{$col};
52 301 50       696 if (! $data) {
53 0         0 $data = $cache->{$col} = $self->{table} ? $self->{table}->call_inflate($col, $self->get_column($col)) : $self->get_column($col);
54             }
55 301         393 return $data;
56 301         414 }
57 301 100       599  
58 267 100       1099 my ($self, $col, $val) = @_;
59             $self->set_column( $col => $val, deflate => 1);
60 301         1641 delete $self->{_get_column_cached}->{$col};
61             return $self;
62             }
63              
64 26     26 1 1674 my ($self, $col) = @_;
65 26         83  
66 26         40 unless ( $col ) {
67 26         49 Carp::croak('please specify $col for first argument');
68             }
69              
70             if ( exists $self->{row_data}->{$col} ) {
71 390     390 1 2494 if (exists $self->{_dirty_columns}->{$col}) {
72             return $self->{_dirty_columns}->{$col};
73 390 100       716 } else {
74 1         114 return $self->{row_data}->{$col};
75             }
76             } else {
77 389 100       753 Carp::croak("Specified column '$col' not found in row (query: " . ( $self->{sql} || 'unknown' ) . ")" );
78 387 100       684 }
79 3         11 }
80              
81 384         1574 my $self = shift;
82              
83             my %data;
84 2   50     123 for my $col ( @{$self->{select_columns}} ) {
85             $data{$col} = $self->get_column($col);
86             }
87             return \%data;
88             }
89 40     40 1 4944  
90             my ($self, $col, $val, %opts) = @_;
91 40         54 if ($opts{deflate} || $self->handle->{force_deflate_set_column}) {
92 40         54 $val = $self->{table}->call_deflate($col, $val);
  40         99  
93 115         181 }
94              
95 40         187 if ( defined $self->{row_data}->{$col}
96             && defined $val
97             && $self->{row_data}->{$col} eq $val ) {
98             if (exists $self->{_dirty_columns}->{$col}) {
99 36     36 1 7549 delete $self->{_dirty_columns}->{$col};
100 36 100 100     128 delete $self->{_get_column_cached}->{$col};
101 28         101 delete $self->{_untrusted_row_data}->{$col};
102             }
103             return $val;
104 36 100 66     319 }
      100        
105              
106             if (ref($val) eq 'SCALAR') {
107 6 100       17 $self->{_untrusted_row_data}->{$col} = 1;
108 1         3 }
109 1         1  
110 1         2 delete $self->{_get_column_cached}->{$col};
111             $self->{_dirty_columns}->{$col} = $val;
112 6         17  
113             $val;
114             }
115 30 100       68  
116 2         4 my ($self, $args) = @_;
117              
118             for my $col (keys %$args) {
119 30         55 $self->set_column($col, $args->{$col});
120 30         57 }
121             }
122 30         49  
123             my $self = shift;
124             +{ %{ $self->{_dirty_columns} } };
125             }
126 1     1 1 2  
127             my $self = shift;
128 1         3 keys %{$self->{_dirty_columns}} > 0
129 1         3 }
130              
131             my ($self, $upd, $where) = @_;
132              
133             if (ref($self) eq 'Teng::Row') {
134 29     29 1 40 Carp::croak q{can't update from basic Teng::Row class.};
135 29         50 }
  29         85  
136              
137             my $table = $self->{table};
138             my $table_name = $self->{table_name};
139 7     7 1 20 if (! $table) {
140 7         8 Carp::croak( "Table definition for $table_name does not exist (Did you declare it in our schema?)" );
  7         34  
141             }
142              
143             if ($upd) {
144 34     34 1 4615 for my $col (keys %$upd) {
145             $self->set($col => $upd->{$col});
146 34 100       133 }
147 1         144 }
148              
149             if ($where) {
150 33         69 $where = {
151 33         58 %$where,
152 33 50       82 %{ $self->_where_cond },
153 0         0 };
154             }
155             else {
156 33 100       100 $where = $self->_where_cond;
157 23         61 }
158 24         105  
159             $upd = $self->get_dirty_columns;
160             return 0 unless %$upd;
161              
162 33 100       76 my $bind_args = $self->handle->_bind_sql_type_to_args($table, $upd);
163             my $result = $self->handle->do_update($table_name, $bind_args, $where, 1);
164             if ($result > 0) {
165 2         5 $self->{row_data} = {
  2         4  
166             %{ $self->{row_data} },
167             %$upd,
168             };
169 31         94 }
170             $self->{_dirty_columns} = {};
171              
172 29         101 $result;
173 29 100       81 }
174              
175 21         80 my $self = shift;
176 21         40  
177 21 50       70 if (ref($self) eq 'Teng::Row') {
178             Carp::croak q{can't delete from basic Teng::Row class.};
179 21         25 }
  21         152  
180              
181             $self->handle->delete($self->{table_name}, $self->_where_cond);
182             }
183 21         71  
184             my ($self, $opt) = @_;
185 21         93 $self->handle->single($self->{table_name}, $self->_where_cond, $opt);
186             }
187              
188             # Generate a where clause to fetch this row itself.
189 15     15 1 5887 my $self = shift;
190              
191 15 100       76 my $table = $self->{table};
192 1         59 my $table_name = $self->{table_name};
193             unless ($table) {
194             Carp::croak("Unknown table: $table_name");
195 14         58 }
196              
197             # get target table pk
198             my $pk = $table->primary_keys;
199 5     5 1 30 unless ($pk) {
200 5         30 Carp::croak("$table_name has no primary key.");
201             }
202              
203             # multi primary keys
204             if ( ref $pk eq 'ARRAY' ) {
205 52     52   75 unless (@$pk) {
206             Carp::croak("$table_name has no primary key.");
207 52         92 }
208 52         80  
209 52 50       187 my %pks = map { $_ => 1 } @$pk;
210 0         0  
211             unless ( ( grep { exists $pks{ $_ } } @{$self->{select_columns}} ) == @$pk ) {
212             Carp::croak "can't get primary columns in your query.";
213             }
214 52         170  
215 52 100       312 return +{ map { $_ => $self->{row_data}->{$_} } @$pk };
216 2         125 } else {
217             unless (grep { $pk eq $_ } @{$self->{select_columns}}) {
218             Carp::croak "can't get primary column in your query.";
219             }
220 50 50       202  
221 50 100       168 return +{ $pk => $self->{row_data}->{$pk} };
222 2         160 }
223             }
224              
225 48         104 # for +columns option by some search methods
  75         211  
226             my $self = shift;
227 48 100       70 my($method) = ($AUTOLOAD =~ /([^:']+$)/);
  164         323  
  48         98  
228 4         349 ($self->{_autoload_column_cache}{$method} ||= $self->generate_column_accessor($method))->($self);
229             }
230              
231 44         123 ### don't autoload this
  71         293  
232             my $self = shift;
233 0 0       0 delete $obj{$self+0};
  0         0  
  0         0  
234 0         0 };
235              
236             1;
237 0         0  
238             =head1 NAME
239              
240             Teng::Row - Teng's Row class
241              
242             =head1 METHODS
243 43     43   1082  
244 43         167 =over
245 43   33     126  
246             =item $row = Teng::Row->new
247              
248             create new Teng::Row's instance
249              
250 268     268   119493 =item $row->get($col)
251 268         2130  
252             my $val = $row->get($column_name);
253              
254             # alias
255             my $val = $row->$column_name;
256              
257             get a column value from a row object.
258              
259             Note: This method inflates values.
260              
261             =item $row->set($col, $val)
262              
263             $row->set($col => $val);
264              
265             set column data.
266              
267             Note: This method deflates values.
268              
269             =item $row->get_column($column_name)
270              
271             my $val = $row->get_column($column_name);
272              
273             get a column value from a row object.
274              
275             Note: This method does not inflate values.
276              
277             =item $row->get_columns
278              
279             my $data = $row->get_columns;
280              
281             Does C<get_column>, for all column values.
282              
283             Note: This method does not inflate values.
284              
285             =item $row->set_columns(\%new_row_data)
286              
287             $row->set_columns({$col => $val});
288              
289             set columns data.
290              
291             Note: This method does not deflate values.
292              
293             =item $row->set_column($col => $val)
294              
295             $row->set_column($col => $val);
296              
297             # alias
298             $row->$col($val);
299              
300             set column data.
301              
302             Note: This method does not deflate values.
303              
304             =item $row->get_dirty_columns
305              
306             returns those that have been changed.
307              
308             =item $row->is_changed
309              
310             returns true, If the row object have a updated column.
311              
312             =item $row->update([$arg : HashRef, $where : HashRef])
313              
314             update is executed for instance record.
315              
316             It works by schema in which primary key exists.
317              
318             $row->update({name => 'tokuhirom'});
319             # or
320             $row->set({name => 'tokuhirom'});
321             $row->update;
322              
323             If C<$arg> is supplied, each pairs are passed to C<set()> method before update.
324              
325             If C<$where> is supplied, each pairs to be merged into default (primary keys) WHERE condition.
326             It is useful for optimistic lock.
327              
328             $row = $teng->single(table_name, {id => 1});
329             $result = $row->update({point => 2}, {point => 1});
330             # UPDATE table_name SET point = 2 WHERE id = 1 AND point = 1;
331              
332             =item $row->delete
333              
334             delete is executed for instance record.
335              
336             It works by schema in which primary key exists.
337              
338             =item my $refetched_row = $row->refetch([$opt:HashRef]);
339              
340             refetch record from database. get new row object.
341              
342             You can specify C<$opt> like C<< { for_update => 1} >> optionally, which is used to build query.
343              
344             =item $row->handle
345              
346             get Teng object.
347              
348             $row->handle->single('table', {id => 1});
349              
350             =back
351              
352             =head1 NOTE FOR COLUMN NAME METHOD
353              
354             Teng::Row has methods that have name from column name. For example, if a table has column named 'foo', Teng::Row instance of it has method 'foo'.
355              
356             This method has different behave for setter or getter as following:
357              
358             # (getter) is alias of $row->get('foo')
359             # so this method returns inflated value.
360             my $inflated_value = $row->foo;
361              
362             # (setter) is alias of $row->set_column('foo', $raw_value)
363             # so this method does not deflate the value. This only accepts raw value but inflated object.
364             $row->foo($raw_value);
365              
366             This behave is from historical reason. You should use column name methods with great caution, if you want to use this.
367              
368             =cut
369