File Coverage

blib/lib/DBIx/Class/InflateColumn.pm
Criterion Covered Total %
statement 45 52 86.5
branch 16 22 72.7
condition 10 21 47.6
subroutine 10 11 90.9
pod 4 4 100.0
total 85 110 77.2


line stmt bran cond sub pod time code
1             package DBIx::Class::InflateColumn;
2              
3 312     312   139895 use strict;
  312         819  
  312         10761  
4 312     312   1877 use warnings;
  312         755  
  312         10735  
5              
6 312     312   1897 use base 'DBIx::Class::Row';
  312         702  
  312         137444  
7 312     312   2359 use SQL::Abstract 'is_literal_value';
  312         715  
  312         15049  
8 312     312   1948 use namespace::clean;
  312         722  
  312         1453  
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 6252     6252 1 20163 my ($self, $col, $attrs) = @_;
89              
90 6252         29931 my $colinfo = $self->result_source->columns_info([$col])->{$col};
91              
92             $self->throw_exception("InflateColumn can not be used on a column with a declared FilterColumn filter")
93 6252 100 66     30721 if defined $colinfo->{_filter_info} and $self->isa('DBIx::Class::FilterColumn');
94              
95 6251 50       20518 $self->throw_exception("inflate_column needs attr hashref")
96             unless ref $attrs eq 'HASH';
97              
98 6251         18357 $colinfo->{_inflate_info} = $attrs;
99 6251         12528 my $acc = $colinfo->{accessor};
100 6251 100       69318 $self->mk_group_accessors('inflated_column' => [ (defined $acc ? $acc : $col), $col]);
101 6251         611298 return 1;
102             }
103              
104             sub _inflated_column {
105 319     319   1040 my ($self, $col, $value) = @_;
106              
107 319 100 66     3024 return $value if (
108             ! defined $value # NULL is NULL is NULL
109             or
110             is_literal_value($value) #that would be a not-yet-reloaded literal update
111             );
112              
113 314         2785 my $info = $self->result_source->columns_info([$col])->{$col};
114              
115 314 50       1554 return $value unless exists $info->{_inflate_info};
116              
117             return (
118             $info->{_inflate_info}{inflate}
119             ||
120 314   33     2444 $self->throw_exception("No inflator found for '$col'")
121             )->($value, $self);
122             }
123              
124             sub _deflated_column {
125 130     130   447 my ($self, $col, $value) = @_;
126              
127             ## Deflate any refs except for literals, pass through plain values
128 130 100 66     896 return $value if (
129             ! length ref $value
130             or
131             is_literal_value($value)
132             );
133              
134 129         1257 my $info = $self->result_source->columns_info([$col])->{$col};
135              
136 129 50       2077 return $value unless exists $info->{_inflate_info};
137              
138             return (
139             $info->{_inflate_info}{deflate}
140             ||
141 129   33     946 $self->throw_exception("No deflator found for '$col'")
142             )->($value, $self);
143             }
144              
145             =head2 get_inflated_column
146              
147             my $val = $obj->get_inflated_column($col);
148              
149             Fetch a column value in its inflated state. This is directly
150             analogous to L in that it only fetches a
151             column already retrieved from the database, and then inflates it.
152             Throws an exception if the column requested is not an inflated column.
153              
154             =cut
155              
156             sub get_inflated_column {
157 436     436 1 35219 my ($self, $col) = @_;
158              
159             $self->throw_exception("$col is not an inflated column")
160 436 50       2369 unless exists $self->result_source->columns_info->{$col}{_inflate_info};
161              
162             # we take care of keeping things in sync
163             return $self->{_inflated_column}{$col}
164 436 100       3943 if exists $self->{_inflated_column}{$col};
165              
166 319         1545 my $val = $self->get_column($col);
167              
168 319         1658 return $self->{_inflated_column}{$col} = $self->_inflated_column($col, $val);
169             }
170              
171             =head2 set_inflated_column
172              
173             my $copy = $obj->set_inflated_column($col => $val);
174              
175             Sets a column value from an inflated value. This is directly
176             analogous to L.
177              
178             =cut
179              
180             sub set_inflated_column {
181 18     18 1 331 my ($self, $col, $value) = @_;
182              
183             # pass through deflated stuff
184 18 100 66     109 if (! length ref $value or is_literal_value($value)) {
185 3         47 $self->set_column($col, $value);
186 3         11 delete $self->{_inflated_column}{$col};
187             }
188             # need to call set_column with the deflate cycle so that
189             # relationship caches are nuked if any
190             # also does the compare-for-dirtyness and change tracking dance
191             else {
192 15         149 $self->set_column($col, $self->_deflated_column($col, $value));
193 15         41 $self->{_inflated_column}{$col} = $value;
194             }
195              
196 18         69 return $value;
197             }
198              
199             =head2 store_inflated_column
200              
201             my $copy = $obj->store_inflated_column($col => $val);
202              
203             Sets a column value from an inflated value without marking the column
204             as dirty. This is directly analogous to L.
205              
206             =cut
207              
208             sub store_inflated_column {
209 0     0 1   my ($self, $col, $value) = @_;
210              
211 0 0 0       if (! length ref $value or is_literal_value($value)) {
212 0           delete $self->{_inflated_column}{$col};
213 0           $self->store_column($col => $value);
214             }
215             else {
216 0           delete $self->{_column_data}{$col};
217 0           $self->{_inflated_column}{$col} = $value;
218             }
219              
220 0           return $value;
221             }
222              
223             =head1 SEE ALSO
224              
225             =over 4
226              
227             =item L - This component is loaded as part of the
228             C L components; generally there is no need to
229             load it directly
230              
231             =back
232              
233             =head1 FURTHER QUESTIONS?
234              
235             Check the list of L.
236              
237             =head1 COPYRIGHT AND LICENSE
238              
239             This module is free software L
240             by the L. You can
241             redistribute it and/or modify it under the same terms as the
242             L.
243              
244             =cut
245              
246             1;