Make sure unaliased selectors and prefetch coexist peacefully
[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
52416317 78 my $colinfo = $self->column_info($col);
79
c227b295 80 $self->throw_exception("InflateColumn does not work with FilterColumn")
81 if $self->isa('DBIx::Class::FilterColumn') &&
52416317 82 defined $colinfo->{_filter_info};
c227b295 83
bc0c9800 84 $self->throw_exception("No such column $col to inflate")
85 unless $self->has_column($col);
86 $self->throw_exception("inflate_column needs attr hashref")
87 unless ref $attrs eq 'HASH';
52416317 88 $colinfo->{_inflate_info} = $attrs;
89 my $acc = $colinfo->{accessor};
b82c8a28 90 $self->mk_group_accessors('inflated_column' => [ (defined $acc ? $acc : $col), $col]);
0e5c2582 91 return 1;
92}
93
4a07648a 94sub _inflated_column {
0e5c2582 95 my ($self, $col, $value) = @_;
9f300b1b 96 return $value unless defined $value; # NULL is NULL is NULL
bc0c9800 97 my $info = $self->column_info($col)
98 or $self->throw_exception("No column info for $col");
103647d5 99 return $value unless exists $info->{_inflate_info};
100 my $inflate = $info->{_inflate_info}{inflate};
701da8c4 101 $self->throw_exception("No inflator for $col") unless defined $inflate;
0e5c2582 102 return $inflate->($value, $self);
103}
104
89279e9d 105sub _deflated_column {
106 my ($self, $col, $value) = @_;
e81a6241 107# return $value unless ref $value && blessed($value); # If it's not an object, don't touch it
108 ## Leave scalar refs (ala SQL::Abstract literal SQL), untouched, deflate all other refs
109 return $value unless (ref $value && ref($value) ne 'SCALAR');
89279e9d 110 my $info = $self->column_info($col) or
111 $self->throw_exception("No column info for $col");
112 return $value unless exists $info->{_inflate_info};
113 my $deflate = $info->{_inflate_info}{deflate};
114 $self->throw_exception("No deflator for $col") unless defined $deflate;
115 return $deflate->($value, $self);
0e5c2582 116}
117
7eb4ecc8 118=head2 get_inflated_column
119
120 my $val = $obj->get_inflated_column($col);
121
122Fetch a column value in its inflated state. This is directly
123analogous to L<DBIx::Class::Row/get_column> in that it only fetches a
48580715 124column already retrieved from the database, and then inflates it.
7eb4ecc8 125Throws an exception if the column requested is not an inflated column.
126
127=cut
128
0e5c2582 129sub get_inflated_column {
130 my ($self, $col) = @_;
bc0c9800 131 $self->throw_exception("$col is not an inflated column")
132 unless exists $self->column_info($col)->{_inflate_info};
0e5c2582 133 return $self->{_inflated_column}{$col}
134 if exists $self->{_inflated_column}{$col};
f92b166e 135
136 my $val = $self->get_column($col);
137 return $val if ref $val eq 'SCALAR'; #that would be a not-yet-reloaded sclarref update
138
139 return $self->{_inflated_column}{$col} = $self->_inflated_column($col, $val);
0e5c2582 140}
141
7eb4ecc8 142=head2 set_inflated_column
143
144 my $copy = $obj->set_inflated_column($col => $val);
145
146Sets a column value from an inflated value. This is directly
147analogous to L<DBIx::Class::Row/set_column>.
148
149=cut
150
0e5c2582 151sub set_inflated_column {
ad5d0ee9 152 my ($self, $col, $inflated) = @_;
153 $self->set_column($col, $self->_deflated_column($col, $inflated));
154# if (blessed $inflated) {
155 if (ref $inflated && ref($inflated) ne 'SCALAR') {
9b2c0de6 156 $self->{_inflated_column}{$col} = $inflated;
9f471067 157 } else {
9b2c0de6 158 delete $self->{_inflated_column}{$col};
9f471067 159 }
ad5d0ee9 160 return $inflated;
0e5c2582 161}
162
7eb4ecc8 163=head2 store_inflated_column
164
165 my $copy = $obj->store_inflated_column($col => $val);
166
167Sets a column value from an inflated value without marking the column
47c56124 168as dirty. This is directly analogous to L<DBIx::Class::Row/store_column>.
7eb4ecc8 169
170=cut
171
0e5c2582 172sub store_inflated_column {
ad5d0ee9 173 my ($self, $col, $inflated) = @_;
174# unless (blessed $inflated) {
175 unless (ref $inflated && ref($inflated) ne 'SCALAR') {
9f471067 176 delete $self->{_inflated_column}{$col};
ad5d0ee9 177 $self->store_column($col => $inflated);
178 return $inflated;
9f471067 179 }
25594f03 180 delete $self->{_column_data}{$col};
ad5d0ee9 181 return $self->{_inflated_column}{$col} = $inflated;
180c7679 182}
4a07648a 183
bcae85db 184=head1 SEE ALSO
185
186=over 4
187
188=item L<DBIx::Class::Core> - This component is loaded as part of the
d88ecca6 189 C<core> L<DBIx::Class> components; generally there is no need to
bcae85db 190 load it directly
191
192=back
193
194=head1 AUTHOR
195
196Matt S. Trout <mst@shadowcatsystems.co.uk>
197
198=head1 CONTRIBUTORS
199
200Daniel Westermann-Clark <danieltwc@cpan.org> (documentation)
201
e81a6241 202Jess Robinson <cpan@desert-island.demon.co.uk>
203
bcae85db 204=head1 LICENSE
205
206You may distribute this code under the same terms as Perl itself.
207
208=cut
209
0e5c2582 2101;