Merge 'trunk' into 'DBIx-Class-current'
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / InflateColumn.pm
CommitLineData
0e5c2582 1package DBIx::Class::InflateColumn;
2
3use strict;
4use warnings;
aa562407 5
aa562407 6
75a23b3e 7use base qw/DBIx::Class::Row/;
0e5c2582 8
bcae85db 9=head1 NAME
10
11DBIx::Class::InflateColumn - Automatically create objects from column data
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
23This component translates column data into objects, i.e. "inflating"
24the column data. It also "deflates" objects into an appropriate format
25for the database.
26
27It can be used, for example, to automatically convert to and from
28L<DateTime> objects for your date and time fields.
29
30=head1 METHODS
31
32=head2 inflate_column
33
34Instruct L<DBIx::Class> to inflate the given column.
35
36In addition to the column name, you must provide C<inflate> and
37C<deflate> methods. The C<inflate> method is called when you access
38the field, while the C<deflate> method is called when the field needs
39to used by the database.
40
41For example, if you have a table C<events> with a timestamp field
42named C<insert_time>, you could inflate the column in the
43corresponding table class using something like:
44
45 __PACKAGE__->inflate_column('insert_time', {
46 inflate => sub { DateTime::Format::Pg->parse_datetime(shift); },
47 deflate => sub { DateTime::Format::Pg->format_datetime(shift); },
48 });
49
50(Replace L<DateTime::Format::Pg> with the appropriate module for your
51database, or consider L<DateTime::Format::DBI>.)
52
53In this example, calls to an event's C<insert_time> accessor return a
54L<DateTime> object. This L<DateTime> object is later "deflated" when
55used in the database layer.
56
57=cut
58
0e5c2582 59sub inflate_column {
60 my ($self, $col, $attrs) = @_;
701da8c4 61 $self->throw_exception("No such column $col to inflate") unless $self->has_column($col);
62 $self->throw_exception("inflate_column needs attr hashref") unless ref $attrs eq 'HASH';
103647d5 63 $self->column_info($col)->{_inflate_info} = $attrs;
0e5c2582 64 $self->mk_group_accessors('inflated_column' => $col);
65 return 1;
66}
67
4a07648a 68sub _inflated_column {
0e5c2582 69 my ($self, $col, $value) = @_;
9f300b1b 70 return $value unless defined $value; # NULL is NULL is NULL
701da8c4 71 my $info = $self->column_info($col) || $self->throw_exception("No column info for $col");
103647d5 72 return $value unless exists $info->{_inflate_info};
73 my $inflate = $info->{_inflate_info}{inflate};
701da8c4 74 $self->throw_exception("No inflator for $col") unless defined $inflate;
0e5c2582 75 return $inflate->($value, $self);
76}
77
4a07648a 78sub _deflated_column {
0e5c2582 79 my ($self, $col, $value) = @_;
80 return $value unless ref $value; # If it's not an object, don't touch it
701da8c4 81 my $info = $self->column_info($col) || $self->throw_exception("No column info for $col");
103647d5 82 return $value unless exists $info->{_inflate_info};
83 my $deflate = $info->{_inflate_info}{deflate};
701da8c4 84 $self->throw_exception("No deflator for $col") unless defined $deflate;
0e5c2582 85 return $deflate->($value, $self);
86}
87
88sub get_inflated_column {
89 my ($self, $col) = @_;
701da8c4 90 $self->throw_exception("$col is not an inflated column") unless
103647d5 91 exists $self->column_info($col)->{_inflate_info};
4a07648a 92
0e5c2582 93 return $self->{_inflated_column}{$col}
94 if exists $self->{_inflated_column}{$col};
0e5c2582 95 return $self->{_inflated_column}{$col} =
4a07648a 96 $self->_inflated_column($col, $self->get_column($col));
0e5c2582 97}
98
99sub set_inflated_column {
100 my ($self, $col, @rest) = @_;
47bd0267 101 my $ret = $self->_inflated_column_op('set', $col, @rest);
0e5c2582 102 return $ret;
103}
104
105sub store_inflated_column {
47bd0267 106 my ($self, $col, @rest) = @_;
107 my $ret = $self->_inflated_column_op('store', $col, @rest);
108 return $ret;
109}
110
111sub _inflated_column_op {
112 my ($self, $op, $col, $obj) = @_;
113 my $meth = "${op}_column";
0e5c2582 114 unless (ref $obj) {
115 delete $self->{_inflated_column}{$col};
47bd0267 116 return $self->$meth($col, $obj);
0e5c2582 117 }
4a07648a 118
119 my $deflated = $self->_deflated_column($col, $obj);
9f300b1b 120 # Do this now so we don't store if it's invalid
4a07648a 121
0e5c2582 122 $self->{_inflated_column}{$col} = $obj;
47bd0267 123 $self->$meth($col, $deflated);
0e5c2582 124 return $obj;
125}
126
9fcda149 127sub update {
128 my ($class, $attrs, @rest) = @_;
129 $attrs ||= {};
130 foreach my $key (keys %$attrs) {
131 if (ref $attrs->{$key}
132 && exists $class->column_info($key)->{_inflate_info}) {
e9100ff7 133# $attrs->{$key} = $class->_deflated_column($key, $attrs->{$key});
134 $class->set_inflated_column ($key, delete $attrs->{$key});
9fcda149 135 }
136 }
137 return $class->next::method($attrs, @rest);
138}
139
0e5c2582 140sub new {
141 my ($class, $attrs, @rest) = @_;
142 $attrs ||= {};
0e5c2582 143 foreach my $key (keys %$attrs) {
103647d5 144 if (ref $attrs->{$key}
145 && exists $class->column_info($key)->{_inflate_info}) {
484c9dda 146 $attrs->{$key} = $class->_deflated_column($key, $attrs->{$key});
0e5c2582 147 }
148 }
147dd158 149 return $class->next::method($attrs, @rest);
0e5c2582 150}
151
bcae85db 152=head1 SEE ALSO
153
154=over 4
155
156=item L<DBIx::Class::Core> - This component is loaded as part of the
157 "core" L<DBIx::Class> components; generally there is no need to
158 load it directly
159
160=back
161
162=head1 AUTHOR
163
164Matt S. Trout <mst@shadowcatsystems.co.uk>
165
166=head1 CONTRIBUTORS
167
168Daniel Westermann-Clark <danieltwc@cpan.org> (documentation)
169
170=head1 LICENSE
171
172You may distribute this code under the same terms as Perl itself.
173
174=cut
175
0e5c2582 1761;