File Coverage

blib/lib/DBIx/Class/InflateColumn.pm
Criterion Covered Total %
statement 46 53 86.7
branch 19 28 67.8
condition 10 21 47.6
subroutine 10 11 90.9
pod 4 4 100.0
total 89 117 76.0


line stmt bran cond sub pod time code
1             package DBIx::Class::InflateColumn;
2              
3 379     379   168836 use strict;
  379         733  
  379         10581  
4 379     379   1505 use warnings;
  379         617  
  379         10343  
5              
6 379     379   1428 use base 'DBIx::Class::Row';
  379         622  
  379         193164  
7 379     379   2484 use SQL::Abstract 'is_literal_value';
  379         753  
  379         17552  
8 379     379   1785 use namespace::clean;
  379         713  
  379         1563  
9              
10             =head1 NAME
11              
12             DBIx::Class::InflateColumn - Automatically create references from column data
13              
14             =head1 SYNOPSIS
15              
16             # In your table classes
17             __PACKAGE__->inflate_column('column_name', {
18             inflate => sub {
19             my ($raw_value_from_db, $result_object) = @_;
20             ...
21             },
22             deflate => sub {
23             my ($inflated_value_from_user, $result_object) = @_;
24             ...
25             },
26             });
27              
28             =head1 DESCRIPTION
29              
30             This component translates column data into references, i.e. "inflating"
31             the column data. It also "deflates" references into an appropriate format
32             for the database.
33              
34             It can be used, for example, to automatically convert to and from
35             L objects for your date and time fields. There's a
36             convenience component to actually do that though, try
37             L.
38              
39             It will handle all types of references except scalar references. It
40             will not handle scalar values, these are ignored and thus passed
41             through to L. This is to allow setting raw values to
42             "just work". Scalar references are passed through to the database to
43             deal with, to allow such settings as C< \'year + 1'> and C< \'DEFAULT' >
44             to work.
45              
46             If you want to filter plain scalar values and replace them with
47             something else, see L.
48              
49             =head1 METHODS
50              
51             =head2 inflate_column
52              
53             Instruct L to inflate the given column.
54              
55             In addition to the column name, you must provide C and
56             C methods. The C method is called when you access
57             the field, while the C method is called when the field needs
58             to used by the database.
59              
60             For example, if you have a table C with a timestamp field
61             named C, you could inflate the column in the
62             corresponding table class using something like:
63              
64             __PACKAGE__->inflate_column('insert_time', {
65             inflate => sub {
66             my ($insert_time_raw_value, $event_result_object) = @_;
67             DateTime->from_epoch( epoch => $insert_time_raw_value );
68             },
69             deflate => sub {
70             my ($insert_time_dt_object, $event_result_object) = @_;
71             $insert_time_dt_object->epoch;
72             },
73             });
74              
75             The coderefs you set for inflate and deflate are called with two parameters,
76             the first is the value of the column to be inflated/deflated, the second is
77             the result object itself.
78              
79             In this example, calls to an event's C accessor return a
80             L object. This L object is later "deflated" back
81             to the integer epoch representation when used in the database layer.
82             For a much more thorough handling of the above example, please see
83             L
84              
85             =cut
86              
87             sub inflate_column {
88 8506     8506 1 18532 my ($self, $col, $attrs) = @_;
89              
90 8506         197241 my $colinfo = $self->column_info($col);
91              
92             $self->throw_exception("InflateColumn can not be used on a column with a declared FilterColumn filter")
93 8506 100 66     24160 if defined $colinfo->{_filter_info} and $self->isa('DBIx::Class::FilterColumn');
94              
95 8505 50       164900 $self->throw_exception("No such column $col to inflate")
96             unless $self->has_column($col);
97 8505 50       23268 $self->throw_exception("inflate_column needs attr hashref")
98             unless ref $attrs eq 'HASH';
99 8505         13798 $colinfo->{_inflate_info} = $attrs;
100 8505         15083 my $acc = $colinfo->{accessor};
101 8505 100       68714 $self->mk_group_accessors('inflated_column' => [ (defined $acc ? $acc : $col), $col]);
102 8505         2505900 return 1;
103             }
104              
105             sub _inflated_column {
106 319     319   602 my ($self, $col, $value) = @_;
107              
108 319 100 66     1807 return $value if (
109             ! defined $value # NULL is NULL is NULL
110             or
111             is_literal_value($value) #that would be a not-yet-reloaded literal update
112             );
113              
114 315 50       2954 my $info = $self->result_source->column_info($col)
115             or $self->throw_exception("No column info for $col");
116              
117 315 50       1099 return $value unless exists $info->{_inflate_info};
118              
119             return (
120             $info->{_inflate_info}{inflate}
121             ||
122 315   33     2199 $self->throw_exception("No inflator found for '$col'")
123             )->($value, $self);
124             }
125              
126             sub _deflated_column {
127 129     129   232 my ($self, $col, $value) = @_;
128              
129             ## Deflate any refs except for literals, pass through plain values
130 129 100 66     746 return $value if (
131             ! length ref $value
132             or
133             is_literal_value($value)
134             );
135              
136 128 50       1193 my $info = $self->result_source->column_info($col) or
137             $self->throw_exception("No column info for $col");
138              
139 128 50       401 return $value unless exists $info->{_inflate_info};
140              
141             return (
142             $info->{_inflate_info}{deflate}
143             ||
144 128   33     762 $self->throw_exception("No deflator found for '$col'")
145             )->($value, $self);
146             }
147              
148             =head2 get_inflated_column
149              
150             my $val = $obj->get_inflated_column($col);
151              
152             Fetch a column value in its inflated state. This is directly
153             analogous to L in that it only fetches a
154             column already retrieved from the database, and then inflates it.
155             Throws an exception if the column requested is not an inflated column.
156              
157             =cut
158              
159             sub get_inflated_column {
160 442     442 1 28371 my ($self, $col) = @_;
161              
162             $self->throw_exception("$col is not an inflated column")
163 442 50       1598 unless exists $self->result_source->column_info($col)->{_inflate_info};
164              
165             # we take care of keeping things in sync
166             return $self->{_inflated_column}{$col}
167 442 100       3294 if exists $self->{_inflated_column}{$col};
168              
169 319         1167 my $val = $self->get_column($col);
170              
171 319         1456 return $self->{_inflated_column}{$col} = $self->_inflated_column($col, $val);
172             }
173              
174             =head2 set_inflated_column
175              
176             my $copy = $obj->set_inflated_column($col => $val);
177              
178             Sets a column value from an inflated value. This is directly
179             analogous to L.
180              
181             =cut
182              
183             sub set_inflated_column {
184 19     19 1 441 my ($self, $col, $value) = @_;
185              
186             # pass through deflated stuff
187 19 100 66     113 if (! length ref $value or is_literal_value($value)) {
188 3         39 $self->set_column($col, $value);
189 3         6 delete $self->{_inflated_column}{$col};
190             }
191             # need to call set_column with the deflate cycle so that
192             # relationship caches are nuked if any
193             # also does the compare-for-dirtyness and change tracking dance
194             else {
195 16         176 $self->set_column($col, $self->_deflated_column($col, $value));
196 16         38 $self->{_inflated_column}{$col} = $value;
197             }
198              
199 19         71 return $value;
200             }
201              
202             =head2 store_inflated_column
203              
204             my $copy = $obj->store_inflated_column($col => $val);
205              
206             Sets a column value from an inflated value without marking the column
207             as dirty. This is directly analogous to L.
208              
209             =cut
210              
211             sub store_inflated_column {
212 0     0 1   my ($self, $col, $value) = @_;
213              
214 0 0 0       if (! length ref $value or is_literal_value($value)) {
215 0           delete $self->{_inflated_column}{$col};
216 0           $self->store_column($col => $value);
217             }
218             else {
219 0           delete $self->{_column_data}{$col};
220 0           $self->{_inflated_column}{$col} = $value;
221             }
222              
223 0           return $value;
224             }
225              
226             =head1 SEE ALSO
227              
228             =over 4
229              
230             =item L - This component is loaded as part of the
231             C L components; generally there is no need to
232             load it directly
233              
234             =back
235              
236             =head1 FURTHER QUESTIONS?
237              
238             Check the list of L.
239              
240             =head1 COPYRIGHT AND LICENSE
241              
242             This module is free software L
243             by the L. You can
244             redistribute it and/or modify it under the same terms as the
245             L.
246              
247             =cut
248              
249             1;