File Coverage

blib/lib/DBIx/Class/InflateColumn.pm
Criterion Covered Total %
statement 53 53 100.0
branch 21 28 75.0
condition 14 21 66.6
subroutine 11 11 100.0
pod 4 4 100.0
total 103 117 88.0


line stmt bran cond sub pod time code
1             package DBIx::Class::InflateColumn;
2              
3 379     379   183514 use strict;
  379         1264  
  379         12041  
4 379     379   2153 use warnings;
  379         1109  
  379         10909  
5              
6 379     379   4197 use base 'DBIx::Class::Row';
  379         1096  
  379         221915  
7 379     379   3466 use SQL::Abstract 'is_literal_value';
  379         1175  
  379         17233  
8 379     379   2464 use namespace::clean;
  379         1137  
  379         1812  
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<DateTime> objects for your date and time fields. There's a
36             convenience component to actually do that though, try
37             L<DBIx::Class::InflateColumn::DateTime>.
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<SQL::Abstract>. 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<DBIx::Class::FilterColumn>.
48              
49             =head1 METHODS
50              
51             =head2 inflate_column
52              
53             Instruct L<DBIx::Class> to inflate the given column.
54              
55             In addition to the column name, you must provide C<inflate> and
56             C<deflate> methods. The C<inflate> method is called when you access
57             the field, while the C<deflate> method is called when the field needs
58             to used by the database.
59              
60             For example, if you have a table C<events> with a timestamp field
61             named C<insert_time>, 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<insert_time> accessor return a
80             L<DateTime> object. This L<DateTime> 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<DBIx::Class::DateTime::Epoch>
84              
85             =cut
86              
87             sub inflate_column {
88 8508     8508 1 34639 my ($self, $col, $attrs) = @_;
89              
90 8508         206027 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 8508 100 66     29122 if defined $colinfo->{_filter_info} and $self->isa('DBIx::Class::FilterColumn');
94              
95 8507 50       168723 $self->throw_exception("No such column $col to inflate")
96             unless $self->has_column($col);
97 8507 50       27185 $self->throw_exception("inflate_column needs attr hashref")
98             unless ref $attrs eq 'HASH';
99 8507         24104 $colinfo->{_inflate_info} = $attrs;
100 8507         15975 my $acc = $colinfo->{accessor};
101 8507 100       72074 $self->mk_group_accessors('inflated_column' => [ (defined $acc ? $acc : $col), $col]);
102 8507         3215526 return 1;
103             }
104              
105             sub _inflated_column {
106 342     342   756 my ($self, $col, $value) = @_;
107              
108 342 100 100     1756 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 332 50       2664 my $info = $self->result_source->column_info($col)
115             or $self->throw_exception("No column info for $col");
116              
117 332 50       970 return $value unless exists $info->{_inflate_info};
118              
119             return (
120             $info->{_inflate_info}{inflate}
121             ||
122 332   33     1763 $self->throw_exception("No inflator found for '$col'")
123             )->($value, $self);
124             }
125              
126             sub _deflated_column {
127 138     138   457 my ($self, $col, $value) = @_;
128              
129             ## Deflate any refs except for literals, pass through plain values
130 138 100 66     908 return $value if (
131             ! length ref $value
132             or
133             is_literal_value($value)
134             );
135              
136 137 50       1436 my $info = $self->result_source->column_info($col) or
137             $self->throw_exception("No column info for $col");
138              
139 137 50       605 return $value unless exists $info->{_inflate_info};
140              
141             return (
142             $info->{_inflate_info}{deflate}
143             ||
144 137   33     895 $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<DBIx::Class::Row/get_column> 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 473     473 1 38782 my ($self, $col) = @_;
161              
162             $self->throw_exception("$col is not an inflated column")
163 473 50       1678 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 473 100       3321 if exists $self->{_inflated_column}{$col};
168              
169 342         1303 my $val = $self->get_column($col);
170              
171 342         1585 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<DBIx::Class::Row/set_column>.
180              
181             =cut
182              
183             sub set_inflated_column {
184 29     29 1 3119 my ($self, $col, $value) = @_;
185              
186             # pass through deflated stuff
187 29 100 100     174 if (! length ref $value or is_literal_value($value)) {
188 8         118 $self->set_column($col, $value);
189 8         42 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 21         251 $self->set_column($col, $self->_deflated_column($col, $value));
196 21         90 $self->{_inflated_column}{$col} = $value;
197             }
198              
199 29         118 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<DBIx::Class::Row/store_column>.
208              
209             =cut
210              
211             sub store_inflated_column {
212 2     2 1 74 my ($self, $col, $value) = @_;
213              
214 2 100 66     14 if (! length ref $value or is_literal_value($value)) {
215 1         11 delete $self->{_inflated_column}{$col};
216 1         5 $self->store_column($col => $value);
217             }
218             else {
219 1         9 delete $self->{_column_data}{$col};
220 1         5 $self->{_inflated_column}{$col} = $value;
221             }
222              
223 2         9 return $value;
224             }
225              
226             =head1 SEE ALSO
227              
228             =over 4
229              
230             =item L<DBIx::Class::Core> - This component is loaded as part of the
231             C<core> L<DBIx::Class> 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<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
239              
240             =head1 COPYRIGHT AND LICENSE
241              
242             This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
243             by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
244             redistribute it and/or modify it under the same terms as the
245             L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
246              
247             =cut
248              
249             1;