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