Restore ability to handle underdefined root (t/prefetch/incomplete.t)
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / InflateColumn.pm
CommitLineData
0e5c2582 1package DBIx::Class::InflateColumn;
2
3use strict;
4use warnings;
aa562407 5
75a23b3e 6use base qw/DBIx::Class::Row/;
0e5c2582 7
75d07914 8=head1 NAME
bcae85db 9
e81a6241 10DBIx::Class::InflateColumn - Automatically create references from column data
bcae85db 11
12=head1 SYNOPSIS
13
1b23a127 14 # In your table classes
15 __PACKAGE__->inflate_column('column_name', {
16 inflate => sub {
17 my ($raw_value_from_db, $result_object) = @_;
18 ...
19 },
20 deflate => sub {
21 my ($inflated_value_from_user, $result_object) = @_;
22 ...
23 },
24 });
bcae85db 25
26=head1 DESCRIPTION
27
e81a6241 28This component translates column data into references, i.e. "inflating"
29the column data. It also "deflates" references into an appropriate format
bcae85db 30for the database.
31
32It can be used, for example, to automatically convert to and from
ef7a8b67 33L<DateTime> objects for your date and time fields. There's a
48580715 34convenience component to actually do that though, try
ef7a8b67 35L<DBIx::Class::InflateColumn::DateTime>.
bcae85db 36
ef7a8b67 37It will handle all types of references except scalar references. It
38will not handle scalar values, these are ignored and thus passed
39through to L<SQL::Abstract>. This is to allow setting raw values to
40"just work". Scalar references are passed through to the database to
41deal with, to allow such settings as C< \'year + 1'> and C< \'DEFAULT' >
42to work.
43
44If you want to filter plain scalar values and replace them with
9b2c0de6 45something else, see L<DBIx::Class::FilterColumn>.
e81a6241 46
bcae85db 47=head1 METHODS
48
49=head2 inflate_column
50
75d07914 51Instruct L<DBIx::Class> to inflate the given column.
bcae85db 52
53In addition to the column name, you must provide C<inflate> and
54C<deflate> methods. The C<inflate> method is called when you access
55the field, while the C<deflate> method is called when the field needs
56to used by the database.
57
58For example, if you have a table C<events> with a timestamp field
59named C<insert_time>, you could inflate the column in the
60corresponding table class using something like:
61
62 __PACKAGE__->inflate_column('insert_time', {
1b23a127 63 inflate => sub {
64 my ($insert_time_raw_value, $event_result_object) = @_;
65 DateTime->from_epoch( epoch => $insert_time_raw_value );
66 },
67 deflate => sub {
68 my ($insert_time_dt_object, $event_result_object) = @_;
69 $insert_time_dt_object->epoch;
70 },
bcae85db 71 });
72
06fc5fc9 73The coderefs you set for inflate and deflate are called with two parameters,
1b23a127 74the first is the value of the column to be inflated/deflated, the second is
75the result object itself.
06fc5fc9 76
bcae85db 77In this example, calls to an event's C<insert_time> accessor return a
1b23a127 78L<DateTime> object. This L<DateTime> object is later "deflated" back
79to the integer epoch representation when used in the database layer.
80For a much more thorough handling of the above example, please see
81L<DBIx::Class::DateTime::Epoch>
bcae85db 82
83=cut
84
0e5c2582 85sub inflate_column {
86 my ($self, $col, $attrs) = @_;
c227b295 87
52416317 88 my $colinfo = $self->column_info($col);
89
c227b295 90 $self->throw_exception("InflateColumn does not work with FilterColumn")
91 if $self->isa('DBIx::Class::FilterColumn') &&
52416317 92 defined $colinfo->{_filter_info};
c227b295 93
bc0c9800 94 $self->throw_exception("No such column $col to inflate")
95 unless $self->has_column($col);
96 $self->throw_exception("inflate_column needs attr hashref")
97 unless ref $attrs eq 'HASH';
52416317 98 $colinfo->{_inflate_info} = $attrs;
99 my $acc = $colinfo->{accessor};
b82c8a28 100 $self->mk_group_accessors('inflated_column' => [ (defined $acc ? $acc : $col), $col]);
0e5c2582 101 return 1;
102}
103
4a07648a 104sub _inflated_column {
0e5c2582 105 my ($self, $col, $value) = @_;
9f300b1b 106 return $value unless defined $value; # NULL is NULL is NULL
bc0c9800 107 my $info = $self->column_info($col)
108 or $self->throw_exception("No column info for $col");
103647d5 109 return $value unless exists $info->{_inflate_info};
110 my $inflate = $info->{_inflate_info}{inflate};
701da8c4 111 $self->throw_exception("No inflator for $col") unless defined $inflate;
0e5c2582 112 return $inflate->($value, $self);
113}
114
89279e9d 115sub _deflated_column {
116 my ($self, $col, $value) = @_;
e81a6241 117# return $value unless ref $value && blessed($value); # If it's not an object, don't touch it
118 ## Leave scalar refs (ala SQL::Abstract literal SQL), untouched, deflate all other refs
119 return $value unless (ref $value && ref($value) ne 'SCALAR');
89279e9d 120 my $info = $self->column_info($col) or
121 $self->throw_exception("No column info for $col");
122 return $value unless exists $info->{_inflate_info};
123 my $deflate = $info->{_inflate_info}{deflate};
124 $self->throw_exception("No deflator for $col") unless defined $deflate;
125 return $deflate->($value, $self);
0e5c2582 126}
127
7eb4ecc8 128=head2 get_inflated_column
129
130 my $val = $obj->get_inflated_column($col);
131
132Fetch a column value in its inflated state. This is directly
133analogous to L<DBIx::Class::Row/get_column> in that it only fetches a
48580715 134column already retrieved from the database, and then inflates it.
7eb4ecc8 135Throws an exception if the column requested is not an inflated column.
136
137=cut
138
0e5c2582 139sub get_inflated_column {
140 my ($self, $col) = @_;
bc0c9800 141 $self->throw_exception("$col is not an inflated column")
142 unless exists $self->column_info($col)->{_inflate_info};
0e5c2582 143 return $self->{_inflated_column}{$col}
144 if exists $self->{_inflated_column}{$col};
f92b166e 145
146 my $val = $self->get_column($col);
147 return $val if ref $val eq 'SCALAR'; #that would be a not-yet-reloaded sclarref update
148
149 return $self->{_inflated_column}{$col} = $self->_inflated_column($col, $val);
0e5c2582 150}
151
7eb4ecc8 152=head2 set_inflated_column
153
154 my $copy = $obj->set_inflated_column($col => $val);
155
156Sets a column value from an inflated value. This is directly
157analogous to L<DBIx::Class::Row/set_column>.
158
159=cut
160
0e5c2582 161sub set_inflated_column {
ad5d0ee9 162 my ($self, $col, $inflated) = @_;
163 $self->set_column($col, $self->_deflated_column($col, $inflated));
164# if (blessed $inflated) {
165 if (ref $inflated && ref($inflated) ne 'SCALAR') {
9b2c0de6 166 $self->{_inflated_column}{$col} = $inflated;
9f471067 167 } else {
9b2c0de6 168 delete $self->{_inflated_column}{$col};
9f471067 169 }
ad5d0ee9 170 return $inflated;
0e5c2582 171}
172
7eb4ecc8 173=head2 store_inflated_column
174
175 my $copy = $obj->store_inflated_column($col => $val);
176
177Sets a column value from an inflated value without marking the column
47c56124 178as dirty. This is directly analogous to L<DBIx::Class::Row/store_column>.
7eb4ecc8 179
180=cut
181
0e5c2582 182sub store_inflated_column {
ad5d0ee9 183 my ($self, $col, $inflated) = @_;
184# unless (blessed $inflated) {
185 unless (ref $inflated && ref($inflated) ne 'SCALAR') {
9f471067 186 delete $self->{_inflated_column}{$col};
ad5d0ee9 187 $self->store_column($col => $inflated);
188 return $inflated;
9f471067 189 }
25594f03 190 delete $self->{_column_data}{$col};
ad5d0ee9 191 return $self->{_inflated_column}{$col} = $inflated;
180c7679 192}
4a07648a 193
bcae85db 194=head1 SEE ALSO
195
196=over 4
197
198=item L<DBIx::Class::Core> - This component is loaded as part of the
d88ecca6 199 C<core> L<DBIx::Class> components; generally there is no need to
bcae85db 200 load it directly
201
202=back
203
204=head1 AUTHOR
205
206Matt S. Trout <mst@shadowcatsystems.co.uk>
207
208=head1 CONTRIBUTORS
209
210Daniel Westermann-Clark <danieltwc@cpan.org> (documentation)
211
e81a6241 212Jess Robinson <cpan@desert-island.demon.co.uk>
213
bcae85db 214=head1 LICENSE
215
216You may distribute this code under the same terms as Perl itself.
217
218=cut
219
0e5c2582 2201;