Fixed dumbass typo in t/lib
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Row.pm
CommitLineData
7624b19f 1package DBIx::Class::Row;
2
3use strict;
4use warnings;
5
aa562407 6use Carp qw/croak/;
7
1edd1722 8use base qw/DBIx::Class/;
9
097d3227 10__PACKAGE__->load_components(qw/AccessorGroup/);
11
12__PACKAGE__->mk_group_accessors('simple' => 'result_source');
8c49f629 13
7624b19f 14=head1 NAME
15
16DBIx::Class::Row - Basic row methods
17
18=head1 SYNOPSIS
19
20=head1 DESCRIPTION
21
22This class is responsible for defining and doing basic operations on rows
23derived from L<DBIx::Class::Table> objects.
24
25=head1 METHODS
26
8091aa91 27=head2 new
7624b19f 28
29 my $obj = My::Class->new($attrs);
30
31Creates a new row object from column => value mappings passed as a hash ref
32
33=cut
34
35sub new {
36 my ($class, $attrs) = @_;
37 $class = ref $class if ref $class;
38 my $new = bless({ _column_data => { } }, $class);
39 if ($attrs) {
40 $new->throw("attrs must be a hashref" ) unless ref($attrs) eq 'HASH';
41 while (my ($k, $v) = each %{$attrs}) {
aa562407 42 croak "No such column $k on $class" unless $class->has_column($k);
484c9dda 43 $new->store_column($k => $v);
7624b19f 44 }
45 }
46 return $new;
47}
48
8091aa91 49=head2 insert
7624b19f 50
51 $obj->insert;
52
53Inserts an object into the database if it isn't already in there. Returns
097d3227 54the object itself. Requires the object's result source to be set, or the
55class to have a result_source_instance method.
7624b19f 56
57=cut
58
59sub insert {
60 my ($self) = @_;
61 return $self if $self->in_storage;
097d3227 62 $self->{result_source} ||= $self->result_source_instance
63 if $self->can('result_source_instance');
64 my $source = $self->{result_source};
aa562407 65 croak "No result_source set on this object; can't insert" unless $source;
7624b19f 66 #use Data::Dumper; warn Dumper($self);
097d3227 67 $source->storage->insert($source->from, { $self->get_columns });
7624b19f 68 $self->in_storage(1);
69 $self->{_dirty_columns} = {};
70 return $self;
71}
72
8091aa91 73=head2 in_storage
7624b19f 74
75 $obj->in_storage; # Get value
76 $obj->in_storage(1); # Set value
77
78Indicated whether the object exists as a row in the database or not
79
80=cut
81
82sub in_storage {
83 my ($self, $val) = @_;
84 $self->{_in_storage} = $val if @_ > 1;
85 return $self->{_in_storage};
86}
87
8091aa91 88=head2 update
7624b19f 89
90 $obj->update;
91
92Must be run on an object that is already in the database; issues an SQL
93UPDATE query to commit any changes to the object to the db if required.
94
95=cut
96
97sub update {
98 my ($self, $upd) = @_;
99 $self->throw( "Not in database" ) unless $self->in_storage;
d7156e50 100 my %to_update = $self->get_dirty_columns;
c01ab172 101 return $self unless keys %to_update;
88cb6a1d 102 my $rows = $self->result_source->storage->update(
103 $self->result_source->from, \%to_update, $self->ident_condition);
7624b19f 104 if ($rows == 0) {
105 $self->throw( "Can't update ${self}: row not found" );
106 } elsif ($rows > 1) {
107 $self->throw("Can't update ${self}: updated more than one row");
108 }
109 $self->{_dirty_columns} = {};
110 return $self;
111}
112
8091aa91 113=head2 delete
7624b19f 114
115 $obj->delete
116
117Deletes the object from the database. The object is still perfectly usable
118accessor-wise etc. but ->in_storage will now return 0 and the object must
119be re ->insert'ed before it can be ->update'ed
120
121=cut
122
123sub delete {
124 my $self = shift;
125 if (ref $self) {
126 $self->throw( "Not in database" ) unless $self->in_storage;
88cb6a1d 127 $self->result_source->storage->delete(
128 $self->result_source->from, $self->ident_condition);
7624b19f 129 $self->in_storage(undef);
7624b19f 130 } else {
aa562407 131 croak "Can't do class delete without a ResultSource instance"
097d3227 132 unless $self->can('result_source_instance');
7624b19f 133 my $attrs = { };
134 if (@_ > 1 && ref $_[$#_] eq 'HASH') {
135 $attrs = { %{ pop(@_) } };
136 }
137 my $query = (ref $_[0] eq 'HASH' ? $_[0] : {@_});
097d3227 138 $self->result_source_instance->resultset->search(@_)->delete;
7624b19f 139 }
140 return $self;
141}
142
8091aa91 143=head2 get_column
7624b19f 144
145 my $val = $obj->get_column($col);
146
8091aa91 147Gets a column value from a row object. Currently, does not do
148any queries; the column must have already been fetched from
149the database and stored in the object.
7624b19f 150
151=cut
152
153sub get_column {
154 my ($self, $column) = @_;
155 $self->throw( "Can't fetch data as class method" ) unless ref $self;
7624b19f 156 return $self->{_column_data}{$column}
157 if exists $self->{_column_data}{$column};
d7156e50 158 $self->throw( "No such column '${column}'" ) unless $self->has_column($column);
7624b19f 159 return undef;
160}
161
8091aa91 162=head2 get_columns
076a6864 163
164 my %data = $obj->get_columns;
165
8091aa91 166Does C<get_column>, for all column values at once.
076a6864 167
168=cut
169
170sub get_columns {
171 my $self = shift;
cb5f2eea 172 return %{$self->{_column_data}};
d7156e50 173}
174
175=head2 get_dirty_columns
176
177 my %data = $obj->get_dirty_columns;
178
179Identical to get_columns but only returns those that have been changed.
180
181=cut
182
183sub get_dirty_columns {
184 my $self = shift;
185 return map { $_ => $self->{_column_data}{$_} }
186 keys %{$self->{_dirty_columns}};
076a6864 187}
188
8091aa91 189=head2 set_column
7624b19f 190
191 $obj->set_column($col => $val);
192
8091aa91 193Sets a column value. If the new value is different from the old one,
194the column is marked as dirty for when you next call $obj->update.
7624b19f 195
196=cut
197
198sub set_column {
199 my $self = shift;
200 my ($column) = @_;
201 my $old = $self->get_column($column);
202 my $ret = $self->store_column(@_);
87772e46 203 $self->{_dirty_columns}{$column} = 1
204 if (defined $old ^ defined $ret) || (defined $old && $old ne $ret);
7624b19f 205 return $ret;
206}
207
8091aa91 208=head2 set_columns
076a6864 209
dc818523 210 my $copy = $orig->set_columns({ $col => $val, ... });
076a6864 211
8091aa91 212Sets more than one column value at once.
076a6864 213
214=cut
215
216sub set_columns {
217 my ($self,$data) = @_;
218 while (my ($col,$val) = each %$data) {
219 $self->set_column($col,$val);
220 }
c01ab172 221 return $self;
076a6864 222}
223
8091aa91 224=head2 copy
076a6864 225
226 my $copy = $orig->copy({ change => $to, ... });
227
8091aa91 228Inserts a new row with the specified changes.
076a6864 229
230=cut
231
c01ab172 232sub copy {
233 my ($self, $changes) = @_;
234 my $new = bless({ _column_data => { %{$self->{_column_data}}} }, ref $self);
235 $new->set_column($_ => $changes->{$_}) for keys %$changes;
236 return $new->insert;
237}
238
8091aa91 239=head2 store_column
7624b19f 240
241 $obj->store_column($col => $val);
242
8091aa91 243Sets a column value without marking it as dirty.
7624b19f 244
245=cut
246
247sub store_column {
248 my ($self, $column, $value) = @_;
249 $self->throw( "No such column '${column}'" )
d7156e50 250 unless exists $self->{_column_data}{$column} || $self->has_column($column);
7624b19f 251 $self->throw( "set_column called for ${column} without value" )
252 if @_ < 3;
253 return $self->{_column_data}{$column} = $value;
254}
255
b52e9bf8 256=head2 inflate_result
257
c01ab172 258 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 259
260Called by ResultSet to inflate a result from storage
261
262=cut
263
264sub inflate_result {
c01ab172 265 my ($class, $source, $me, $prefetch) = @_;
b52e9bf8 266 #use Data::Dumper; print Dumper(@_);
c01ab172 267 my $new = bless({ result_source => $source,
268 _column_data => $me,
269 _in_storage => 1
270 },
271 ref $class || $class);
7fb16f1a 272 my $schema;
b52e9bf8 273 PRE: foreach my $pre (keys %{$prefetch||{}}) {
0dc79249 274 my $pre_source = $source->related_source($pre);
aa562407 275 croak "Can't prefetch non-existant relationship ${pre}" unless $pre_source;
0dc79249 276 my $fetched = $pre_source->result_class->inflate_result(
277 $pre_source, @{$prefetch->{$pre}});
278 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
b52e9bf8 279 $class->throw("No accessor for prefetched $pre")
0dc79249 280 unless defined $accessor;
281 PRIMARY: foreach my $pri ($pre_source->primary_columns) {
2fb09619 282 unless (defined $fetched->get_column($pri)) {
283 undef $fetched;
284 last PRIMARY;
b52e9bf8 285 }
2fb09619 286 }
0dc79249 287 if ($accessor eq 'single') {
b52e9bf8 288 $new->{_relationship_data}{$pre} = $fetched;
0dc79249 289 } elsif ($accessor eq 'filter') {
b52e9bf8 290 $new->{_inflated_column}{$pre} = $fetched;
291 } else {
292 $class->throw("Don't know how to store prefetched $pre");
293 }
294 }
7624b19f 295 return $new;
296}
297
8091aa91 298=head2 insert_or_update
7624b19f 299
300 $obj->insert_or_update
301
8091aa91 302Updates the object if it's already in the db, else inserts it.
7624b19f 303
304=cut
305
306sub insert_or_update {
307 my $self = shift;
308 return ($self->in_storage ? $self->update : $self->insert);
309}
310
8091aa91 311=head2 is_changed
7624b19f 312
313 my @changed_col_names = $obj->is_changed
314
315=cut
316
317sub is_changed {
318 return keys %{shift->{_dirty_columns} || {}};
319}
320
097d3227 321=head2 result_source
322
323 Accessor to the ResultSource this object was created from
324
71e65b39 325=head2 register_column($column, $column_info)
1f23a877 326
327 Registers a column on the class and creates an accessor for it
328
097d3227 329=cut
330
1f23a877 331sub register_column {
332 my ($class, $col, $info) = @_;
333 $class->mk_group_accessors('column' => $col);
334}
335
7624b19f 3361;
337
7624b19f 338=head1 AUTHORS
339
daec44b8 340Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 341
342=head1 LICENSE
343
344You may distribute this code under the same terms as Perl itself.
345
346=cut
347