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