* Added myself to the contributors list.
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Row.pm
CommitLineData
7624b19f 1package DBIx::Class::Row;
2
3use strict;
4use warnings;
5
1edd1722 6use base qw/DBIx::Class/;
701da8c4 7use Carp::Clan qw/^DBIx::Class/;
33dd4e80 8use Scalar::Util ();
9c6d6d93 9use Scope::Guard;
1edd1722 10
aec3eff1 11__PACKAGE__->mk_group_accessors('simple' => qw/_source_handle/);
8c49f629 12
75d07914 13=head1 NAME
7624b19f 14
15DBIx::Class::Row - Basic row methods
16
17=head1 SYNOPSIS
18
19=head1 DESCRIPTION
20
21This class is responsible for defining and doing basic operations on rows
1ea77c14 22derived from L<DBIx::Class::ResultSource> objects.
7624b19f 23
a2531bf2 24Row objects are returned from L<DBIx::Class::ResultSet>s using the
ea36f4e4 25L<create|DBIx::Class::ResultSet/create>, L<find|DBIx::Class::ResultSet/find>,
26L<next|DBIx::Class::ResultSet/next> and L<all|DBIx::Class::ResultSet/all> methods,
27as well as invocations of 'single' (
28L<belongs_to|DBIx::Class::Relationship/belongs_to>,
29L<has_one|DBIx::Class::Relationship/has_one> or
30L<might_have|DBIx::Class::Relationship/might_have>)
31relationship accessors of L<DBIx::Class::Row> objects.
a2531bf2 32
7624b19f 33=head1 METHODS
34
8091aa91 35=head2 new
7624b19f 36
a2531bf2 37 my $row = My::Class->new(\%attrs);
38
39 my $row = $schema->resultset('MySource')->new(\%colsandvalues);
40
41=over
42
43=item Arguments: \%attrs or \%colsandvalues
44
45=item Returns: A Row object
7624b19f 46
a2531bf2 47=back
48
49While you can create a new row object by calling C<new> directly on
50this class, you are better off calling it on a
51L<DBIx::Class::ResultSet> object.
52
53When calling it directly, you will not get a complete, usable row
54object until you pass or set the C<source_handle> attribute, to a
55L<DBIx::Class::ResultSource> instance that is attached to a
56L<DBIx::Class::Schema> with a valid connection.
57
58C<$attrs> is a hashref of column name, value data. It can also contain
59some other attributes such as the C<source_handle>.
7624b19f 60
33dd4e80 61Passing an object, or an arrayref of objects as a value will call
62L<DBIx::Class::Relationship::Base/set_from_related> for you. When
63passed a hashref or an arrayref of hashrefs as the value, these will
64be turned into objects via new_related, and treated as if you had
65passed objects.
66
264f1571 67For a more involved explanation, see L<DBIx::Class::ResultSet/create>.
68
7624b19f 69=cut
70
33dd4e80 71## It needs to store the new objects somewhere, and call insert on that list later when insert is called on this object. We may need an accessor for these so the user can retrieve them, if just doing ->new().
72## This only works because DBIC doesnt yet care to check whether the new_related objects have been passed all their mandatory columns
73## When doing the later insert, we need to make sure the PKs are set.
74## using _relationship_data in new and funky ways..
75## check Relationship::CascadeActions and Relationship::Accessor for compat
76## tests!
77
370f2ba2 78sub __new_related_find_or_new_helper {
79 my ($self, $relname, $data) = @_;
80 if ($self->__their_pk_needs_us($relname, $data)) {
81 return $self->result_source
82 ->related_source($relname)
83 ->resultset
84 ->new_result($data);
85 }
86 if ($self->result_source->pk_depends_on($relname, $data)) {
87 return $self->result_source
88 ->related_source($relname)
89 ->resultset
76b8cf98 90 ->find_or_create($data);
370f2ba2 91 }
92 return $self->find_or_new_related($relname, $data);
93}
94
95sub __their_pk_needs_us { # this should maybe be in resultsource.
96 my ($self, $relname, $data) = @_;
97 my $source = $self->result_source;
98 my $reverse = $source->reverse_relationship_info($relname);
99 my $rel_source = $source->related_source($relname);
100 my $us = { $self->get_columns };
101 foreach my $key (keys %$reverse) {
102 # if their primary key depends on us, then we have to
103 # just create a result and we'll fill it out afterwards
104 return 1 if $rel_source->pk_depends_on($key, $us);
105 }
106 return 0;
107}
108
7624b19f 109sub new {
448f820f 110 my ($class, $attrs) = @_;
7624b19f 111 $class = ref $class if ref $class;
04786a4c 112
e60dc79f 113 my $new = {
114 _column_data => {},
115 };
04786a4c 116 bless $new, $class;
117
448f820f 118 if (my $handle = delete $attrs->{-source_handle}) {
119 $new->_source_handle($handle);
120 }
370f2ba2 121
122 my $source;
123 if ($source = delete $attrs->{-result_source}) {
e9fe476b 124 $new->result_source($source);
125 }
a6a280b9 126
7624b19f 127 if ($attrs) {
27f01d1f 128 $new->throw_exception("attrs must be a hashref")
129 unless ref($attrs) eq 'HASH';
61a622ee 130
131 my ($related,$inflated);
de7c7c53 132 ## Pretend all the rels are actual objects, unset below if not, for insert() to fix
133 $new->{_rel_in_storage} = 1;
8222f722 134
61a622ee 135 foreach my $key (keys %$attrs) {
136 if (ref $attrs->{$key}) {
af2d42c0 137 ## Can we extract this lot to use with update(_or .. ) ?
370f2ba2 138 confess "Can't do multi-create without result source" unless $source;
139 my $info = $source->relationship_info($key);
61a622ee 140 if ($info && $info->{attrs}{accessor}
c4a30d56 141 && $info->{attrs}{accessor} eq 'single')
61a622ee 142 {
de7c7c53 143 my $rel_obj = delete $attrs->{$key};
33dd4e80 144 if(!Scalar::Util::blessed($rel_obj)) {
370f2ba2 145 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 146 }
2bc3c81e 147
148 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
149
370f2ba2 150 $new->set_from_related($key, $rel_obj) if $rel_obj->in_storage;
de7c7c53 151 $related->{$key} = $rel_obj;
61a622ee 152 next;
33dd4e80 153 } elsif ($info && $info->{attrs}{accessor}
154 && $info->{attrs}{accessor} eq 'multi'
155 && ref $attrs->{$key} eq 'ARRAY') {
2ec8e594 156 my $others = delete $attrs->{$key};
157 foreach my $rel_obj (@$others) {
158 if(!Scalar::Util::blessed($rel_obj)) {
370f2ba2 159 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 160 }
2bc3c81e 161
162 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
370f2ba2 163 $new->set_from_related($key, $rel_obj) if $rel_obj->in_storage;
2ec8e594 164 }
165 $related->{$key} = $others;
166 next;
167 } elsif ($info && $info->{attrs}{accessor}
168 && $info->{attrs}{accessor} eq 'filter')
61a622ee 169 {
33dd4e80 170 ## 'filter' should disappear and get merged in with 'single' above!
2ec8e594 171 my $rel_obj = delete $attrs->{$key};
33dd4e80 172 if(!Scalar::Util::blessed($rel_obj)) {
370f2ba2 173 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 174 }
370f2ba2 175 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
33dd4e80 176 $inflated->{$key} = $rel_obj;
61a622ee 177 next;
2ec8e594 178 } elsif ($class->has_column($key)
179 && $class->column_info($key)->{_inflate_info}) {
61a622ee 180 $inflated->{$key} = $attrs->{$key};
181 next;
182 }
183 }
184 $new->throw_exception("No such column $key on $class")
185 unless $class->has_column($key);
186 $new->store_column($key => $attrs->{$key});
7624b19f 187 }
f90375dd 188
61a622ee 189 $new->{_relationship_data} = $related if $related;
190 $new->{_inflated_column} = $inflated if $inflated;
7624b19f 191 }
04786a4c 192
7624b19f 193 return $new;
194}
195
8091aa91 196=head2 insert
7624b19f 197
a2531bf2 198 $row->insert;
199
200=over
7624b19f 201
a2531bf2 202=item Arguments: none
203
204=item Returns: The Row object
205
206=back
207
208Inserts an object previously created by L</new> into the database if
209it isn't already in there. Returns the object itself. Requires the
210object's result source to be set, or the class to have a
211result_source_instance method. To insert an entirely new row into
212the database, use C<create> (see L<DBIx::Class::ResultSet/create>).
7624b19f 213
e91e756c 214To fetch an uninserted row object, call
215L<new|DBIx::Class::ResultSet/new> on a resultset.
216
264f1571 217This will also insert any uninserted, related objects held inside this
218one, see L<DBIx::Class::ResultSet/create> for more details.
219
7624b19f 220=cut
221
222sub insert {
223 my ($self) = @_;
224 return $self if $self->in_storage;
6aba697f 225 my $source = $self->result_source;
226 $source ||= $self->result_source($self->result_source_instance)
097d3227 227 if $self->can('result_source_instance');
aeb1bf75 228 $self->throw_exception("No result_source set on this object; can't insert")
229 unless $source;
6e399b4f 230
9c6d6d93 231 my $rollback_guard;
232
33dd4e80 233 # Check if we stored uninserted relobjs here in new()
33dd4e80 234 my %related_stuff = (%{$self->{_relationship_data} || {}},
235 %{$self->{_inflated_column} || {}});
9c6d6d93 236
ae66ef47 237 if(!$self->{_rel_in_storage}) {
8222f722 238
9c6d6d93 239 # The guard will save us if we blow out of this scope via die
1bc193ac 240 $rollback_guard = $source->storage->txn_scope_guard;
9c6d6d93 241
8222f722 242 ## Should all be in relationship_data, but we need to get rid of the
243 ## 'filter' reltype..
244 ## These are the FK rels, need their IDs for the insert.
9c6d6d93 245
246 my @pri = $self->primary_columns;
247
248 REL: foreach my $relname (keys %related_stuff) {
a8c98174 249
250 my $rel_obj = $related_stuff{$relname};
251
252 next REL unless (Scalar::Util::blessed($rel_obj)
253 && $rel_obj->isa('DBIx::Class::Row'));
254
370f2ba2 255 next REL unless $source->pk_depends_on(
256 $relname, { $rel_obj->get_columns }
257 );
9c6d6d93 258
a8c98174 259 $rel_obj->insert();
260 $self->set_from_related($relname, $rel_obj);
261 delete $related_stuff{$relname};
33dd4e80 262 }
263 }
6e399b4f 264
ef5f6b0a 265 my $updated_cols = $source->storage->insert($source, { $self->get_columns });
266 $self->set_columns($updated_cols);
ac8e89d7 267
268 ## PK::Auto
3fda409f 269 my @auto_pri = grep {
270 !defined $self->get_column($_) ||
271 ref($self->get_column($_)) eq 'SCALAR'
272 } $self->primary_columns;
273
274 if (@auto_pri) {
275 #$self->throw_exception( "More than one possible key found for auto-inc on ".ref $self )
276 # if defined $too_many;
ac8e89d7 277
278 my $storage = $self->result_source->storage;
279 $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" )
280 unless $storage->can('last_insert_id');
3fda409f 281 my @ids = $storage->last_insert_id($self->result_source,@auto_pri);
282 $self->throw_exception( "Can't get last insert id" )
283 unless (@ids == @auto_pri);
284 $self->store_column($auto_pri[$_] => $ids[$_]) for 0 .. $#ids;
ac8e89d7 285 }
33dd4e80 286
370f2ba2 287 $self->{_dirty_columns} = {};
288 $self->{related_resultsets} = {};
289
ae66ef47 290 if(!$self->{_rel_in_storage}) {
8222f722 291 ## Now do the has_many rels, that need $selfs ID.
292 foreach my $relname (keys %related_stuff) {
9c6d6d93 293 my $rel_obj = $related_stuff{$relname};
294 my @cands;
295 if (Scalar::Util::blessed($rel_obj)
296 && $rel_obj->isa('DBIx::Class::Row')) {
297 @cands = ($rel_obj);
298 } elsif (ref $rel_obj eq 'ARRAY') {
299 @cands = @$rel_obj;
300 }
301 if (@cands) {
302 my $reverse = $source->reverse_relationship_info($relname);
303 foreach my $obj (@cands) {
304 $obj->set_from_related($_, $self) for keys %$reverse;
e912f5f0 305 my $them = { %{$obj->{_relationship_data} || {} }, $obj->get_inflated_columns };
370f2ba2 306 if ($self->__their_pk_needs_us($relname, $them)) {
307 $obj = $self->find_or_create_related($relname, $them);
308 } else {
309 $obj->insert();
310 }
8222f722 311 }
33dd4e80 312 }
313 }
1bc193ac 314 $rollback_guard->commit;
33dd4e80 315 }
33dd4e80 316
7624b19f 317 $self->in_storage(1);
729b29ae 318 undef $self->{_orig_ident};
7624b19f 319 return $self;
320}
321
8091aa91 322=head2 in_storage
7624b19f 323
a2531bf2 324 $row->in_storage; # Get value
325 $row->in_storage(1); # Set value
326
327=over
328
329=item Arguments: none or 1|0
330
331=item Returns: 1|0
332
333=back
7624b19f 334
e91e756c 335Indicates whether the object exists as a row in the database or
336not. This is set to true when L<DBIx::Class::ResultSet/find>,
337L<DBIx::Class::ResultSet/create> or L<DBIx::Class::ResultSet/insert>
338are used.
339
340Creating a row object using L<DBIx::Class::ResultSet/new>, or calling
341L</delete> on one, sets it to false.
7624b19f 342
343=cut
344
345sub in_storage {
346 my ($self, $val) = @_;
347 $self->{_in_storage} = $val if @_ > 1;
348 return $self->{_in_storage};
349}
350
8091aa91 351=head2 update
7624b19f 352
a2531bf2 353 $row->update(\%columns?)
354
355=over
7624b19f 356
a2531bf2 357=item Arguments: none or a hashref
7624b19f 358
a2531bf2 359=item Returns: The Row object
360
361=back
362
363Throws an exception if the row object is not yet in the database,
364according to L</in_storage>.
365
366This method issues an SQL UPDATE query to commit any changes to the
367object to the database if required.
368
369Also takes an optional hashref of C<< column_name => value> >> pairs
370to update on the object first. Be aware that the hashref will be
371passed to C<set_inflated_columns>, which might edit it in place, so
372don't rely on it being the same after a call to C<update>. If you
373need to preserve the hashref, it is sufficient to pass a shallow copy
374to C<update>, e.g. ( { %{ $href } } )
d5d833d9 375
05d1bc9c 376If the values passed or any of the column values set on the object
377contain scalar references, eg:
378
a2531bf2 379 $row->last_modified(\'NOW()');
05d1bc9c 380 # OR
a2531bf2 381 $row->update({ last_modified => \'NOW()' });
05d1bc9c 382
383The update will pass the values verbatim into SQL. (See
384L<SQL::Abstract> docs). The values in your Row object will NOT change
385as a result of the update call, if you want the object to be updated
386with the actual values from the database, call L</discard_changes>
387after the update.
388
a2531bf2 389 $row->update()->discard_changes();
390
391To determine before calling this method, which column values have
392changed and will be updated, call L</get_dirty_columns>.
393
394To check if any columns will be updated, call L</is_changed>.
395
396To force a column to be updated, call L</make_column_dirty> before
397this method.
05d1bc9c 398
7624b19f 399=cut
400
401sub update {
402 my ($self, $upd) = @_;
701da8c4 403 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 404 my $ident_cond = $self->ident_condition;
405 $self->throw_exception("Cannot safely update a row in a PK-less table")
406 if ! keys %$ident_cond;
6e399b4f 407
bacf6f12 408 $self->set_inflated_columns($upd) if $upd;
5a9e0e60 409 my %to_update = $self->get_dirty_columns;
410 return $self unless keys %to_update;
88cb6a1d 411 my $rows = $self->result_source->storage->update(
f4afcd5d 412 $self->result_source, \%to_update,
413 $self->{_orig_ident} || $ident_cond
414 );
7624b19f 415 if ($rows == 0) {
701da8c4 416 $self->throw_exception( "Can't update ${self}: row not found" );
7624b19f 417 } elsif ($rows > 1) {
701da8c4 418 $self->throw_exception("Can't update ${self}: updated more than one row");
7624b19f 419 }
420 $self->{_dirty_columns} = {};
64acc2bc 421 $self->{related_resultsets} = {};
729b29ae 422 undef $self->{_orig_ident};
7624b19f 423 return $self;
424}
425
8091aa91 426=head2 delete
7624b19f 427
a2531bf2 428 $row->delete
429
430=over
431
432=item Arguments: none
7624b19f 433
a2531bf2 434=item Returns: The Row object
435
436=back
437
438Throws an exception if the object is not in the database according to
439L</in_storage>. Runs an SQL DELETE statement using the primary key
440values to locate the row.
441
442The object is still perfectly usable, but L</in_storage> will
ea36f4e4 443now return 0 and the object must be reinserted using L</insert>
a2531bf2 444before it can be used to L</update> the row again.
445
446If you delete an object in a class with a C<has_many> relationship, an
447attempt is made to delete all the related objects as well. To turn
448this behaviour off, pass C<< cascade_delete => 0 >> in the C<$attr>
449hashref of the relationship, see L<DBIx::Class::Relationship>. Any
450database-level cascade or restrict will take precedence over a
451DBIx-Class-based cascading delete.
452
453See also L<DBIx::Class::ResultSet/delete>.
7624b19f 454
455=cut
456
457sub delete {
458 my $self = shift;
459 if (ref $self) {
701da8c4 460 $self->throw_exception( "Not in database" ) unless $self->in_storage;
728e60a3 461 my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
4b12b3c2 462 $self->throw_exception("Cannot safely delete a row in a PK-less table")
463 if ! keys %$ident_cond;
e0f56292 464 foreach my $column (keys %$ident_cond) {
75d07914 465 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
466 unless exists $self->{_column_data}{$column};
e0f56292 467 }
88cb6a1d 468 $self->result_source->storage->delete(
7af8b477 469 $self->result_source, $ident_cond);
7624b19f 470 $self->in_storage(undef);
7624b19f 471 } else {
701da8c4 472 $self->throw_exception("Can't do class delete without a ResultSource instance")
097d3227 473 unless $self->can('result_source_instance');
aeb1bf75 474 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
475 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
097d3227 476 $self->result_source_instance->resultset->search(@_)->delete;
7624b19f 477 }
478 return $self;
479}
480
8091aa91 481=head2 get_column
7624b19f 482
a2531bf2 483 my $val = $row->get_column($col);
484
485=over
486
487=item Arguments: $columnname
488
489=item Returns: The value of the column
490
491=back
492
493Throws an exception if the column name given doesn't exist according
494to L</has_column>.
7624b19f 495
e91e756c 496Returns a raw column value from the row object, if it has already
497been fetched from the database or set by an accessor.
498
499If an L<inflated value|DBIx::Class::InflateColumn> has been set, it
500will be deflated and returned.
7624b19f 501
ea36f4e4 502Note that if you used the C<columns> or the C<select/as>
503L<search attributes|DBIx::Class::ResultSet/ATTRIBUTES> on the resultset from
504which C<$row> was derived, and B<did not include> C<$columnname> in the list,
505this method will return C<undef> even if the database contains some value.
506
a2531bf2 507To retrieve all loaded column values as a hash, use L</get_columns>.
508
7624b19f 509=cut
510
511sub get_column {
512 my ($self, $column) = @_;
701da8c4 513 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
aeb1bf75 514 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
61a622ee 515 if (exists $self->{_inflated_column}{$column}) {
516 return $self->store_column($column,
517 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
518 }
701da8c4 519 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
7624b19f 520 return undef;
521}
522
9b83fccd 523=head2 has_column_loaded
524
a2531bf2 525 if ( $row->has_column_loaded($col) ) {
9b83fccd 526 print "$col has been loaded from db";
527 }
528
a2531bf2 529=over
530
531=item Arguments: $columnname
532
533=item Returns: 0|1
534
535=back
536
9b83fccd 537Returns a true value if the column value has been loaded from the
538database (or set locally).
539
540=cut
541
def81720 542sub has_column_loaded {
543 my ($self, $column) = @_;
544 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
61a622ee 545 return 1 if exists $self->{_inflated_column}{$column};
aeb1bf75 546 return exists $self->{_column_data}{$column};
def81720 547}
548
8091aa91 549=head2 get_columns
076a6864 550
a2531bf2 551 my %data = $row->get_columns;
552
553=over
554
555=item Arguments: none
076a6864 556
a2531bf2 557=item Returns: A hash of columnname, value pairs.
558
559=back
560
561Returns all loaded column data as a hash, containing raw values. To
562get just one value for a particular column, use L</get_column>.
076a6864 563
564=cut
565
566sub get_columns {
567 my $self = shift;
61a622ee 568 if (exists $self->{_inflated_column}) {
569 foreach my $col (keys %{$self->{_inflated_column}}) {
570 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
c4a30d56 571 unless exists $self->{_column_data}{$col};
61a622ee 572 }
573 }
cb5f2eea 574 return %{$self->{_column_data}};
d7156e50 575}
576
577=head2 get_dirty_columns
578
a2531bf2 579 my %data = $row->get_dirty_columns;
580
581=over
582
583=item Arguments: none
d7156e50 584
a2531bf2 585=item Returns: A hash of column, value pairs
586
587=back
588
589Only returns the column, value pairs for those columns that have been
590changed on this object since the last L</update> or L</insert> call.
591
592See L</get_columns> to fetch all column/value pairs.
d7156e50 593
594=cut
595
596sub get_dirty_columns {
597 my $self = shift;
598 return map { $_ => $self->{_column_data}{$_} }
599 keys %{$self->{_dirty_columns}};
076a6864 600}
601
6dbea98e 602=head2 make_column_dirty
603
a2531bf2 604 $row->make_column_dirty($col)
605
606=over
607
608=item Arguments: $columnname
609
610=item Returns: undefined
611
612=back
613
614Throws an exception if the column does not exist.
615
616Marks a column as having been changed regardless of whether it has
617really changed.
6dbea98e 618
619=cut
620sub make_column_dirty {
621 my ($self, $column) = @_;
622
623 $self->throw_exception( "No such column '${column}'" )
624 unless exists $self->{_column_data}{$column} || $self->has_column($column);
625 $self->{_dirty_columns}{$column} = 1;
626}
627
ba4a6453 628=head2 get_inflated_columns
629
e91e756c 630 my %inflated_data = $obj->get_inflated_columns;
ba4a6453 631
a2531bf2 632=over
633
634=item Arguments: none
635
636=item Returns: A hash of column, object|value pairs
637
638=back
639
640Returns a hash of all column keys and associated values. Values for any
641columns set to use inflation will be inflated and returns as objects.
642
643See L</get_columns> to get the uninflated values.
644
645See L<DBIx::Class::InflateColumn> for how to setup inflation.
ba4a6453 646
647=cut
648
649sub get_inflated_columns {
650 my $self = shift;
651 return map {
652 my $accessor = $self->column_info($_)->{'accessor'} || $_;
653 ($_ => $self->$accessor);
654 } $self->columns;
655}
656
8091aa91 657=head2 set_column
7624b19f 658
a2531bf2 659 $row->set_column($col => $val);
660
661=over
662
663=item Arguments: $columnname, $value
664
665=item Returns: $value
666
667=back
7624b19f 668
e91e756c 669Sets a raw column value. If the new value is different from the old one,
a2531bf2 670the column is marked as dirty for when you next call L</update>.
7624b19f 671
ea36f4e4 672If passed an object or reference as a value, this method will happily
673attempt to store it, and a later L</insert> or L</update> will try and
a2531bf2 674stringify/numify as appropriate. To set an object to be deflated
675instead, see L</set_inflated_columns>.
e91e756c 676
7624b19f 677=cut
678
679sub set_column {
1d0057bd 680 my ($self, $column, $new_value) = @_;
681
729b29ae 682 $self->{_orig_ident} ||= $self->ident_condition;
1d0057bd 683 my $old_value = $self->get_column($column);
684
685 $self->store_column($column, $new_value);
87772e46 686 $self->{_dirty_columns}{$column} = 1
1d0057bd 687 if (defined $old_value xor defined $new_value) || (defined $old_value && $old_value ne $new_value);
e60dc79f 688
689 # XXX clear out the relation cache for this column
690 delete $self->{related_resultsets}{$column};
691
1d0057bd 692 return $new_value;
7624b19f 693}
694
8091aa91 695=head2 set_columns
076a6864 696
a2531bf2 697 $row->set_columns({ $col => $val, ... });
698
699=over
076a6864 700
a2531bf2 701=item Arguments: \%columndata
702
703=item Returns: The Row object
704
705=back
706
707Sets multiple column, raw value pairs at once.
708
709Works as L</set_column>.
076a6864 710
711=cut
712
713sub set_columns {
714 my ($self,$data) = @_;
a2ca474b 715 foreach my $col (keys %$data) {
716 $self->set_column($col,$data->{$col});
076a6864 717 }
c01ab172 718 return $self;
076a6864 719}
720
bacf6f12 721=head2 set_inflated_columns
722
a2531bf2 723 $row->set_inflated_columns({ $col => $val, $relname => $obj, ... });
724
725=over
726
727=item Arguments: \%columndata
728
729=item Returns: The Row object
730
731=back
732
733Sets more than one column value at once. Any inflated values are
734deflated and the raw values stored.
bacf6f12 735
a2531bf2 736Any related values passed as Row objects, using the relation name as a
737key, are reduced to the appropriate foreign key values and stored. If
738instead of related row objects, a hashref of column, value data is
739passed, will create the related object first then store.
740
741Will even accept arrayrefs of data as a value to a
742L<DBIx::Class::Relationship/has_many> key, and create the related
743objects if necessary.
744
745Be aware that the input hashref might be edited in place, so dont rely
746on it being the same after a call to C<set_inflated_columns>. If you
747need to preserve the hashref, it is sufficient to pass a shallow copy
748to C<set_inflated_columns>, e.g. ( { %{ $href } } )
749
750See also L<DBIx::Class::Relationship::Base/set_from_related>.
bacf6f12 751
752=cut
753
754sub set_inflated_columns {
755 my ( $self, $upd ) = @_;
756 foreach my $key (keys %$upd) {
757 if (ref $upd->{$key}) {
758 my $info = $self->relationship_info($key);
759 if ($info && $info->{attrs}{accessor}
760 && $info->{attrs}{accessor} eq 'single')
761 {
762 my $rel = delete $upd->{$key};
763 $self->set_from_related($key => $rel);
a7be8807 764 $self->{_relationship_data}{$key} = $rel;
bacf6f12 765 } elsif ($info && $info->{attrs}{accessor}
a7be8807 766 && $info->{attrs}{accessor} eq 'multi') {
767 $self->throw_exception(
768 "Recursive update is not supported over relationships of type multi ($key)"
769 );
bacf6f12 770 }
771 elsif ($self->has_column($key)
772 && exists $self->column_info($key)->{_inflate_info})
773 {
a7be8807 774 $self->set_inflated_column($key, delete $upd->{$key});
bacf6f12 775 }
776 }
777 }
778 $self->set_columns($upd);
779}
780
8091aa91 781=head2 copy
076a6864 782
783 my $copy = $orig->copy({ change => $to, ... });
784
a2531bf2 785=over
786
787=item Arguments: \%replacementdata
788
789=item Returns: The Row object copy
790
791=back
792
793Inserts a new row into the database, as a copy of the original
794object. If a hashref of replacement data is supplied, these will take
795precedence over data in the original.
796
797If the row has related objects in a
798L<DBIx::Class::Relationship/has_many> then those objects may be copied
799too depending on the L<cascade_copy|DBIx::Class::Relationship>
800relationship attribute.
076a6864 801
802=cut
803
c01ab172 804sub copy {
805 my ($self, $changes) = @_;
333cce60 806 $changes ||= {};
fde6e28e 807 my $col_data = { %{$self->{_column_data}} };
808 foreach my $col (keys %$col_data) {
809 delete $col_data->{$col}
810 if $self->result_source->column_info($col)->{is_auto_increment};
811 }
04786a4c 812
813 my $new = { _column_data => $col_data };
814 bless $new, ref $self;
815
83419ec6 816 $new->result_source($self->result_source);
bacf6f12 817 $new->set_inflated_columns($changes);
333cce60 818 $new->insert;
35688220 819
820 # Its possible we'll have 2 relations to the same Source. We need to make
821 # sure we don't try to insert the same row twice esle we'll violate unique
822 # constraints
823 my $rels_copied = {};
824
333cce60 825 foreach my $rel ($self->result_source->relationships) {
826 my $rel_info = $self->result_source->relationship_info($rel);
35688220 827
828 next unless $rel_info->{attrs}{cascade_copy};
829
830 my $resolved = $self->result_source->resolve_condition(
831 $rel_info->{cond}, $rel, $new
832 );
833
834 my $copied = $rels_copied->{ $rel_info->{source} } ||= {};
835 foreach my $related ($self->search_related($rel)) {
836 my $id_str = join("\0", $related->id);
837 next if $copied->{$id_str};
838 $copied->{$id_str} = 1;
839 my $rel_copy = $related->copy($resolved);
333cce60 840 }
35688220 841
333cce60 842 }
2c4c67b6 843 return $new;
c01ab172 844}
845
8091aa91 846=head2 store_column
7624b19f 847
a2531bf2 848 $row->store_column($col => $val);
7624b19f 849
a2531bf2 850=over
851
852=item Arguments: $columnname, $value
853
ea36f4e4 854=item Returns: The value sent to storage
a2531bf2 855
856=back
857
858Set a raw value for a column without marking it as changed. This
859method is used internally by L</set_column> which you should probably
860be using.
861
862This is the lowest level at which data is set on a row object,
863extend this method to catch all data setting methods.
7624b19f 864
865=cut
866
867sub store_column {
868 my ($self, $column, $value) = @_;
75d07914 869 $self->throw_exception( "No such column '${column}'" )
d7156e50 870 unless exists $self->{_column_data}{$column} || $self->has_column($column);
75d07914 871 $self->throw_exception( "set_column called for ${column} without value" )
7624b19f 872 if @_ < 3;
873 return $self->{_column_data}{$column} = $value;
874}
875
b52e9bf8 876=head2 inflate_result
877
c01ab172 878 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 879
a2531bf2 880=over
881
882=item Arguments: $result_source, \%columndata, \%prefetcheddata
883
884=item Returns: A Row object
885
886=back
887
888All L<DBIx::Class::ResultSet> methods that retrieve data from the
889database and turn it into row objects call this method.
890
891Extend this method in your Result classes to hook into this process,
892for example to rebless the result into a different class.
893
894Reblessing can also be done more easily by setting C<result_class> in
895your Result class. See L<DBIx::Class::ResultSource/result_class>.
b52e9bf8 896
897=cut
898
899sub inflate_result {
c01ab172 900 my ($class, $source, $me, $prefetch) = @_;
aec3eff1 901
902 my ($source_handle) = $source;
903
904 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
905 $source = $source_handle->resolve
906 } else {
907 $source_handle = $source->handle
908 }
909
04786a4c 910 my $new = {
aec3eff1 911 _source_handle => $source_handle,
04786a4c 912 _column_data => $me,
913 _in_storage => 1
914 };
915 bless $new, (ref $class || $class);
916
7fb16f1a 917 my $schema;
64acc2bc 918 foreach my $pre (keys %{$prefetch||{}}) {
919 my $pre_val = $prefetch->{$pre};
f9cc31dd 920 my $pre_source = $source->related_source($pre);
a86b1efe 921 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
922 unless $pre_source;
0f66a01b 923 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
a86b1efe 924 my @pre_objects;
925 foreach my $pre_rec (@$pre_val) {
75d07914 926 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
5a5bec6c 927 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
a86b1efe 928 next;
929 }
930 push(@pre_objects, $pre_source->result_class->inflate_result(
931 $pre_source, @{$pre_rec}));
932 }
933 $new->related_resultset($pre)->set_cache(\@pre_objects);
62e87ea8 934 } elsif (defined $pre_val->[0]) {
a86b1efe 935 my $fetched;
75d07914 936 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
a86b1efe 937 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
938 {
939 $fetched = $pre_source->result_class->inflate_result(
75d07914 940 $pre_source, @{$pre_val});
a86b1efe 941 }
9809a6df 942 $new->related_resultset($pre)->set_cache([ $fetched ]);
a86b1efe 943 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
944 $class->throw_exception("No accessor for prefetched $pre")
945 unless defined $accessor;
946 if ($accessor eq 'single') {
947 $new->{_relationship_data}{$pre} = $fetched;
948 } elsif ($accessor eq 'filter') {
949 $new->{_inflated_column}{$pre} = $fetched;
950 } else {
951 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
952 }
b52e9bf8 953 }
954 }
7624b19f 955 return $new;
956}
957
9b465d00 958=head2 update_or_insert
7624b19f 959
a2531bf2 960 $row->update_or_insert
961
962=over
7624b19f 963
a2531bf2 964=item Arguments: none
965
966=item Returns: Result of update or insert operation
967
968=back
969
970L</Update>s the object if it's already in the database, according to
971L</in_storage>, else L</insert>s it.
7624b19f 972
9b83fccd 973=head2 insert_or_update
974
975 $obj->insert_or_update
976
977Alias for L</update_or_insert>
978
7624b19f 979=cut
980
370f2ba2 981sub insert_or_update { shift->update_or_insert(@_) }
982
9b465d00 983sub update_or_insert {
7624b19f 984 my $self = shift;
985 return ($self->in_storage ? $self->update : $self->insert);
986}
987
8091aa91 988=head2 is_changed
7624b19f 989
a2531bf2 990 my @changed_col_names = $row->is_changed();
991 if ($row->is_changed()) { ... }
992
993=over
7624b19f 994
a2531bf2 995=item Arguments: none
996
997=item Returns: 0|1 or @columnnames
998
999=back
1000
1001In list context returns a list of columns with uncommited changes, or
9b83fccd 1002in scalar context returns a true value if there are uncommitted
1003changes.
1004
7624b19f 1005=cut
1006
1007sub is_changed {
1008 return keys %{shift->{_dirty_columns} || {}};
1009}
228dbcb4 1010
1011=head2 is_column_changed
1012
a2531bf2 1013 if ($row->is_column_changed('col')) { ... }
1014
1015=over
1016
1017=item Arguments: $columname
1018
1019=item Returns: 0|1
1020
1021=back
228dbcb4 1022
9b83fccd 1023Returns a true value if the column has uncommitted changes.
1024
228dbcb4 1025=cut
1026
1027sub is_column_changed {
1028 my( $self, $col ) = @_;
1029 return exists $self->{_dirty_columns}->{$col};
1030}
7624b19f 1031
097d3227 1032=head2 result_source
1033
a2531bf2 1034 my $resultsource = $row->result_source;
1035
1036=over
1037
1038=item Arguments: none
097d3227 1039
a2531bf2 1040=item Returns: a ResultSource instance
1041
1042=back
1043
1044Accessor to the L<DBIx::Class::ResultSource> this object was created from.
87c4e602 1045
aec3eff1 1046=cut
1047
1048sub result_source {
1049 my $self = shift;
1050
1051 if (@_) {
1052 $self->_source_handle($_[0]->handle);
1053 } else {
1054 $self->_source_handle->resolve;
1055 }
1056}
1057
9b83fccd 1058=head2 register_column
27f01d1f 1059
9b83fccd 1060 $column_info = { .... };
1061 $class->register_column($column_name, $column_info);
27f01d1f 1062
a2531bf2 1063=over
1064
1065=item Arguments: $columnname, \%columninfo
1066
1067=item Returns: undefined
1068
1069=back
1070
9b83fccd 1071Registers a column on the class. If the column_info has an 'accessor'
1072key, creates an accessor named after the value if defined; if there is
1073no such key, creates an accessor with the same name as the column
1f23a877 1074
9b83fccd 1075The column_info attributes are described in
1076L<DBIx::Class::ResultSource/add_columns>
1f23a877 1077
097d3227 1078=cut
1079
1f23a877 1080sub register_column {
1081 my ($class, $col, $info) = @_;
91b0fbd7 1082 my $acc = $col;
1083 if (exists $info->{accessor}) {
1084 return unless defined $info->{accessor};
1085 $acc = [ $info->{accessor}, $col ];
1086 }
1087 $class->mk_group_accessors('column' => $acc);
1f23a877 1088}
1089
a2531bf2 1090=head2 get_from_storage
1091
1092 my $copy = $row->get_from_storage($attrs)
1093
1094=over
b9b4e52f 1095
a2531bf2 1096=item Arguments: \%attrs
b9b4e52f 1097
a2531bf2 1098=item Returns: A Row object
1099
1100=back
1101
1102Fetches a fresh copy of the Row object from the database and returns it.
1103
1104If passed the \%attrs argument, will first apply these attributes to
1105the resultset used to find the row.
1106
1107This copy can then be used to compare to an existing row object, to
1108determine if any changes have been made in the database since it was
1109created.
1110
1111To just update your Row object with any latest changes from the
1112database, use L</discard_changes> instead.
1113
1114The \%attrs argument should be compatible with
1115L<DBIx::Class::ResultSet/ATTRIBUTES>.
7e38d850 1116
b9b4e52f 1117=cut
1118
a737512c 1119sub get_from_storage {
b9b4e52f 1120 my $self = shift @_;
7e38d850 1121 my $attrs = shift @_;
7e38d850 1122 my $resultset = $self->result_source->resultset;
1123
1124 if(defined $attrs) {
1125 $resultset = $resultset->search(undef, $attrs);
1126 }
1127
728e60a3 1128 return $resultset->find($self->{_orig_ident} || $self->ident_condition);
b9b4e52f 1129}
701da8c4 1130
5160b401 1131=head2 throw_exception
701da8c4 1132
a2531bf2 1133See L<DBIx::Class::Schema/throw_exception>.
701da8c4 1134
1135=cut
1136
1137sub throw_exception {
1138 my $self=shift;
66cab05c 1139 if (ref $self && ref $self->result_source && $self->result_source->schema) {
701da8c4 1140 $self->result_source->schema->throw_exception(@_);
1141 } else {
1142 croak(@_);
1143 }
1144}
1145
33cf6616 1146=head2 id
1147
a2531bf2 1148 my @pk = $row->id;
1149
1150=over
1151
1152=item Arguments: none
1153
1154=item Returns: A list of primary key values
1155
1156=back
1157
33cf6616 1158Returns the primary key(s) for a row. Can't be called as a class method.
f7043881 1159Actually implemented in L<DBIx::Class::PK>
33cf6616 1160
1161=head2 discard_changes
1162
a2531bf2 1163 $row->discard_changes
1164
1165=over
1166
1167=item Arguments: none
1168
1169=item Returns: nothing (updates object in-place)
1170
1171=back
1172
1173Retrieves and sets the row object data from the database, losing any
1174local changes made.
33cf6616 1175
1176This method can also be used to refresh from storage, retrieving any
1177changes made since the row was last read from storage. Actually
f7043881 1178implemented in L<DBIx::Class::PK>
33cf6616 1179
1180=cut
1181
7624b19f 11821;
1183
7624b19f 1184=head1 AUTHORS
1185
daec44b8 1186Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 1187
1188=head1 LICENSE
1189
1190You may distribute this code under the same terms as Perl itself.
1191
1192=cut