deprecated add_row_info and added replacement method build_metadata
[dbsrgits/DBIx-Class-ResultSet-WithMetaData.git] / lib / DBIx / Class / ResultSet / WithMetaData.pm
1 package DBIx::Class::ResultSet::WithMetaData;
2
3 use strict;
4 use warnings;
5
6 use Data::Alias;
7 use Moose;
8 use Method::Signatures::Simple;
9 extends 'DBIx::Class::ResultSet';
10
11 has '_row_info' => (
12   is => 'rw',
13   isa => 'HashRef'
14 );
15
16 has 'was_row' => (
17   is => 'rw',
18   isa => 'Int'
19 );
20
21 has 'id_cols' => (
22   is => 'rw',
23   isa => 'ArrayRef',
24 );
25
26 has '_modifiers' => (
27   is => 'rw',
28   isa => 'ArrayRef',
29 );
30
31 =head1 VERSION
32
33 Version 0.999003
34
35 =cut
36
37 our $VERSION = '0.999003';
38
39 =head1 NAME
40
41 DBIx::Class::ResultSet::WithMetaData
42
43 =head1 SYNOPSIS
44
45   package MyApp::Schema::ResultSet::ObjectType;
46
47   use Moose;
48   use MooseX::Method::Signatures;
49   extends 'DBIx::Class::ResultSet::WithMetaData;
50
51   method with_substr () {
52     $self->build_metadata( modifier => sub () {
53       my $row = shift;
54       my $substr = substr($row->{name}, 0, 3);
55       $row->{substr} = $substr;
56       return $row;
57     });
58     return $self;
59   }
60
61   ...
62
63
64   # then somewhere else
65
66   my $object_type_arrayref = $object_type_rs->with_substr->display();
67
68   # [{
69   #    'artistid' => '1',
70   #    'name' => 'Caterwauler McCrae',
71   #    'substr' => 'Cat'
72   #  },
73   #  {
74   #    'artistid' => '2',
75   #    'name' => 'Random Boy Band',
76   #    'substr' => 'Ran'
77   #  },
78   #  {
79   #    'artistid' => '3',
80   #    'name' => 'We Are Goth',
81   #    'substr' => 'We '
82   #  }]
83
84 =head1 DESCRIPTION
85
86 Attach metadata to rows by chaining ResultSet methods together. When the ResultSet is
87 flattened to an ArrayRef the attached metadata is merged with the row hashes to give
88 a combined 'hash-plus-other-stuff' representation.
89
90 =head1 METHODS
91
92 =cut
93
94 sub new {
95   my $self = shift;
96
97   my $new = $self->next::method(@_);
98   foreach my $key (qw/_row_info was_row id_cols _modifiers/) {
99     alias $new->{$key} = $new->{attrs}{$key};
100   }
101
102   unless ($new->_row_info) {
103     $new->_row_info({});
104   }
105
106   unless ($new->_modifiers) {
107     $new->_modifiers([]);
108   }
109
110   unless ($new->id_cols && scalar(@{$new->id_cols})) {
111     $new->id_cols([sort $new->result_source->primary_columns]);
112   }
113
114   return $new;
115 }
116
117 =head2 display
118
119 =over 4
120
121 =item Arguments: none
122
123 =item Return Value: ArrayRef
124
125 =back
126
127  $arrayref_of_row_hashrefs = $rs->display();
128
129 This method uses L<DBIx::Class::ResultClass::HashRefInflator> to convert all
130 rows in the ResultSet to HashRefs. These are then merged with any metadata
131 that had been attached to the rows using L</add_row_info>.
132
133 =cut
134
135 method display () {
136   my $rs = $self->search({});
137   $rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
138   my @rows;
139   foreach my $row ($rs->all) {
140     # THIS BLOCK IS DEPRECATED
141     if (my $info = $self->row_info_for(id => $self->_mk_id(row => $row))) {
142       $row = { %{$row}, %{$info} };
143     }
144
145     foreach my $modifier (@{$rs->_modifiers}) {
146       my $new_row = $modifier->($row);
147       if (ref $new_row ne 'HASH') {
148         die 'modifier subref (added via build_metadata did not return hashref)';
149       }
150       $row = $new_row;
151     }
152     push(@rows, $row);
153   }
154
155   return ($self->was_row) ? $rows[0] : \@rows;
156 }
157
158 =head2 build_metadata
159
160 =over 4
161
162 =item Arguments: modifier => subref($row_hash)
163
164 =item Return Value: ResultSet
165
166 =back
167
168  $self->build_metadata( modifier => sub ($row) { 
169    $row->{dates} = [qw/mon weds fri/];
170    return $row;
171  });
172
173 This method allows you to alter the hash to add additional metadata to it
174 at L</display> time.
175
176 =cut
177
178 method build_metadata (%opts) {
179   my ($modifier) = map { $opts{$_} } qw/modifier/;
180   unless ($modifier && (ref $modifier eq 'CODE')) {
181     die 'build_metadata called without modifier param';
182   }
183
184   push( @{$self->_modifiers}, $modifier );
185 }
186
187
188 =head2 add_row_info (DEPRECATED)
189
190 =over 4
191
192 =item Arguments: row => DBIx::Class::Row object, info => HashRef to attach to the row
193
194 =item Return Value: ResultSet
195
196 =back
197
198  $rs = $rs->add_row_info(row => $row, info => { dates => [qw/mon weds fri/] } );
199
200 DEPRECATED - this method is quite slow as it requires that you iterate through 
201 the resultset each time you want to add metadata. Replaced by L</build_metadata>.
202
203 =cut
204
205 method add_row_info (%opts) {
206   my ($row, $id, $info) = map { $opts{$_} } qw/row id info/;
207
208   warn 'DEPRECATED - add_row_info is deprecated in favour of build_metadata';
209   if ($row) {
210     $id = $self->_mk_id(row => { $row->get_columns });
211   }
212
213   unless ($row || $self->find($id)) {
214     die 'invalid id passed to add_row_info';
215   }
216
217   if (my $existing = $self->_row_info->{$id}) {
218     $info = { %{$existing}, %{$info} };
219   }
220
221   $self->_row_info->{$id} = $info;  
222 }
223
224 # DEPRECATED
225 method row_info_for (%opts) {
226   my $id = $opts{id};
227   return $self->_row_info->{$id};
228 }
229
230 # DEPRECATED
231 method _mk_id (%opts) {
232   my $row = $opts{row};
233   return join('-', map { $row->{$_} } @{$self->id_cols});
234 }
235
236 =head1 AUTHOR
237
238   Luke Saunders <luke.saunders@gmail.com>
239
240 =head1 THANKS
241
242 As usual, thanks to Matt S Trout for the sanity check.
243
244 =head1 LICENSE
245
246   This library is free software under the same license as perl itself
247
248 =cut
249
250 1;