Extend might_have test with ideas from zby
[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);
764 $self->{_relationship_data}{$key} = $rel;
765 } elsif ($info && $info->{attrs}{accessor}
766 && $info->{attrs}{accessor} eq 'multi'
767 && ref $upd->{$key} eq 'ARRAY') {
768 my $others = delete $upd->{$key};
769 foreach my $rel_obj (@$others) {
770 if(!Scalar::Util::blessed($rel_obj)) {
771 $rel_obj = $self->create_related($key, $rel_obj);
772 }
773 }
774 $self->{_relationship_data}{$key} = $others;
775# $related->{$key} = $others;
776 next;
777 }
778 elsif ($self->has_column($key)
779 && exists $self->column_info($key)->{_inflate_info})
780 {
781 $self->set_inflated_column($key, delete $upd->{$key});
782 }
783 }
784 }
785 $self->set_columns($upd);
786}
787
8091aa91 788=head2 copy
076a6864 789
790 my $copy = $orig->copy({ change => $to, ... });
791
a2531bf2 792=over
793
794=item Arguments: \%replacementdata
795
796=item Returns: The Row object copy
797
798=back
799
800Inserts a new row into the database, as a copy of the original
801object. If a hashref of replacement data is supplied, these will take
802precedence over data in the original.
803
804If the row has related objects in a
805L<DBIx::Class::Relationship/has_many> then those objects may be copied
806too depending on the L<cascade_copy|DBIx::Class::Relationship>
807relationship attribute.
076a6864 808
809=cut
810
c01ab172 811sub copy {
812 my ($self, $changes) = @_;
333cce60 813 $changes ||= {};
fde6e28e 814 my $col_data = { %{$self->{_column_data}} };
815 foreach my $col (keys %$col_data) {
816 delete $col_data->{$col}
817 if $self->result_source->column_info($col)->{is_auto_increment};
818 }
04786a4c 819
820 my $new = { _column_data => $col_data };
821 bless $new, ref $self;
822
83419ec6 823 $new->result_source($self->result_source);
bacf6f12 824 $new->set_inflated_columns($changes);
333cce60 825 $new->insert;
35688220 826
827 # Its possible we'll have 2 relations to the same Source. We need to make
828 # sure we don't try to insert the same row twice esle we'll violate unique
829 # constraints
830 my $rels_copied = {};
831
333cce60 832 foreach my $rel ($self->result_source->relationships) {
833 my $rel_info = $self->result_source->relationship_info($rel);
35688220 834
835 next unless $rel_info->{attrs}{cascade_copy};
836
837 my $resolved = $self->result_source->resolve_condition(
838 $rel_info->{cond}, $rel, $new
839 );
840
841 my $copied = $rels_copied->{ $rel_info->{source} } ||= {};
842 foreach my $related ($self->search_related($rel)) {
843 my $id_str = join("\0", $related->id);
844 next if $copied->{$id_str};
845 $copied->{$id_str} = 1;
846 my $rel_copy = $related->copy($resolved);
333cce60 847 }
35688220 848
333cce60 849 }
2c4c67b6 850 return $new;
c01ab172 851}
852
8091aa91 853=head2 store_column
7624b19f 854
a2531bf2 855 $row->store_column($col => $val);
7624b19f 856
a2531bf2 857=over
858
859=item Arguments: $columnname, $value
860
ea36f4e4 861=item Returns: The value sent to storage
a2531bf2 862
863=back
864
865Set a raw value for a column without marking it as changed. This
866method is used internally by L</set_column> which you should probably
867be using.
868
869This is the lowest level at which data is set on a row object,
870extend this method to catch all data setting methods.
7624b19f 871
872=cut
873
874sub store_column {
875 my ($self, $column, $value) = @_;
75d07914 876 $self->throw_exception( "No such column '${column}'" )
d7156e50 877 unless exists $self->{_column_data}{$column} || $self->has_column($column);
75d07914 878 $self->throw_exception( "set_column called for ${column} without value" )
7624b19f 879 if @_ < 3;
880 return $self->{_column_data}{$column} = $value;
881}
882
b52e9bf8 883=head2 inflate_result
884
c01ab172 885 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 886
a2531bf2 887=over
888
889=item Arguments: $result_source, \%columndata, \%prefetcheddata
890
891=item Returns: A Row object
892
893=back
894
895All L<DBIx::Class::ResultSet> methods that retrieve data from the
896database and turn it into row objects call this method.
897
898Extend this method in your Result classes to hook into this process,
899for example to rebless the result into a different class.
900
901Reblessing can also be done more easily by setting C<result_class> in
902your Result class. See L<DBIx::Class::ResultSource/result_class>.
b52e9bf8 903
904=cut
905
906sub inflate_result {
c01ab172 907 my ($class, $source, $me, $prefetch) = @_;
aec3eff1 908
909 my ($source_handle) = $source;
910
911 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
912 $source = $source_handle->resolve
913 } else {
914 $source_handle = $source->handle
915 }
916
04786a4c 917 my $new = {
aec3eff1 918 _source_handle => $source_handle,
04786a4c 919 _column_data => $me,
920 _in_storage => 1
921 };
922 bless $new, (ref $class || $class);
923
7fb16f1a 924 my $schema;
64acc2bc 925 foreach my $pre (keys %{$prefetch||{}}) {
926 my $pre_val = $prefetch->{$pre};
f9cc31dd 927 my $pre_source = $source->related_source($pre);
a86b1efe 928 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
929 unless $pre_source;
0f66a01b 930 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
a86b1efe 931 my @pre_objects;
932 foreach my $pre_rec (@$pre_val) {
75d07914 933 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
5a5bec6c 934 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
a86b1efe 935 next;
936 }
937 push(@pre_objects, $pre_source->result_class->inflate_result(
938 $pre_source, @{$pre_rec}));
939 }
940 $new->related_resultset($pre)->set_cache(\@pre_objects);
62e87ea8 941 } elsif (defined $pre_val->[0]) {
a86b1efe 942 my $fetched;
75d07914 943 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
a86b1efe 944 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
945 {
946 $fetched = $pre_source->result_class->inflate_result(
75d07914 947 $pre_source, @{$pre_val});
a86b1efe 948 }
9809a6df 949 $new->related_resultset($pre)->set_cache([ $fetched ]);
a86b1efe 950 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
951 $class->throw_exception("No accessor for prefetched $pre")
952 unless defined $accessor;
953 if ($accessor eq 'single') {
954 $new->{_relationship_data}{$pre} = $fetched;
955 } elsif ($accessor eq 'filter') {
956 $new->{_inflated_column}{$pre} = $fetched;
957 } else {
958 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
959 }
b52e9bf8 960 }
961 }
7624b19f 962 return $new;
963}
964
9b465d00 965=head2 update_or_insert
7624b19f 966
a2531bf2 967 $row->update_or_insert
968
969=over
7624b19f 970
a2531bf2 971=item Arguments: none
972
973=item Returns: Result of update or insert operation
974
975=back
976
977L</Update>s the object if it's already in the database, according to
978L</in_storage>, else L</insert>s it.
7624b19f 979
9b83fccd 980=head2 insert_or_update
981
982 $obj->insert_or_update
983
984Alias for L</update_or_insert>
985
7624b19f 986=cut
987
370f2ba2 988sub insert_or_update { shift->update_or_insert(@_) }
989
9b465d00 990sub update_or_insert {
7624b19f 991 my $self = shift;
992 return ($self->in_storage ? $self->update : $self->insert);
993}
994
8091aa91 995=head2 is_changed
7624b19f 996
a2531bf2 997 my @changed_col_names = $row->is_changed();
998 if ($row->is_changed()) { ... }
999
1000=over
7624b19f 1001
a2531bf2 1002=item Arguments: none
1003
1004=item Returns: 0|1 or @columnnames
1005
1006=back
1007
1008In list context returns a list of columns with uncommited changes, or
9b83fccd 1009in scalar context returns a true value if there are uncommitted
1010changes.
1011
7624b19f 1012=cut
1013
1014sub is_changed {
1015 return keys %{shift->{_dirty_columns} || {}};
1016}
228dbcb4 1017
1018=head2 is_column_changed
1019
a2531bf2 1020 if ($row->is_column_changed('col')) { ... }
1021
1022=over
1023
1024=item Arguments: $columname
1025
1026=item Returns: 0|1
1027
1028=back
228dbcb4 1029
9b83fccd 1030Returns a true value if the column has uncommitted changes.
1031
228dbcb4 1032=cut
1033
1034sub is_column_changed {
1035 my( $self, $col ) = @_;
1036 return exists $self->{_dirty_columns}->{$col};
1037}
7624b19f 1038
097d3227 1039=head2 result_source
1040
a2531bf2 1041 my $resultsource = $row->result_source;
1042
1043=over
1044
1045=item Arguments: none
097d3227 1046
a2531bf2 1047=item Returns: a ResultSource instance
1048
1049=back
1050
1051Accessor to the L<DBIx::Class::ResultSource> this object was created from.
87c4e602 1052
aec3eff1 1053=cut
1054
1055sub result_source {
1056 my $self = shift;
1057
1058 if (@_) {
1059 $self->_source_handle($_[0]->handle);
1060 } else {
1061 $self->_source_handle->resolve;
1062 }
1063}
1064
9b83fccd 1065=head2 register_column
27f01d1f 1066
9b83fccd 1067 $column_info = { .... };
1068 $class->register_column($column_name, $column_info);
27f01d1f 1069
a2531bf2 1070=over
1071
1072=item Arguments: $columnname, \%columninfo
1073
1074=item Returns: undefined
1075
1076=back
1077
9b83fccd 1078Registers a column on the class. If the column_info has an 'accessor'
1079key, creates an accessor named after the value if defined; if there is
1080no such key, creates an accessor with the same name as the column
1f23a877 1081
9b83fccd 1082The column_info attributes are described in
1083L<DBIx::Class::ResultSource/add_columns>
1f23a877 1084
097d3227 1085=cut
1086
1f23a877 1087sub register_column {
1088 my ($class, $col, $info) = @_;
91b0fbd7 1089 my $acc = $col;
1090 if (exists $info->{accessor}) {
1091 return unless defined $info->{accessor};
1092 $acc = [ $info->{accessor}, $col ];
1093 }
1094 $class->mk_group_accessors('column' => $acc);
1f23a877 1095}
1096
a2531bf2 1097=head2 get_from_storage
1098
1099 my $copy = $row->get_from_storage($attrs)
1100
1101=over
b9b4e52f 1102
a2531bf2 1103=item Arguments: \%attrs
b9b4e52f 1104
a2531bf2 1105=item Returns: A Row object
1106
1107=back
1108
1109Fetches a fresh copy of the Row object from the database and returns it.
1110
1111If passed the \%attrs argument, will first apply these attributes to
1112the resultset used to find the row.
1113
1114This copy can then be used to compare to an existing row object, to
1115determine if any changes have been made in the database since it was
1116created.
1117
1118To just update your Row object with any latest changes from the
1119database, use L</discard_changes> instead.
1120
1121The \%attrs argument should be compatible with
1122L<DBIx::Class::ResultSet/ATTRIBUTES>.
7e38d850 1123
b9b4e52f 1124=cut
1125
a737512c 1126sub get_from_storage {
b9b4e52f 1127 my $self = shift @_;
7e38d850 1128 my $attrs = shift @_;
7e38d850 1129 my $resultset = $self->result_source->resultset;
1130
1131 if(defined $attrs) {
1132 $resultset = $resultset->search(undef, $attrs);
1133 }
1134
728e60a3 1135 return $resultset->find($self->{_orig_ident} || $self->ident_condition);
b9b4e52f 1136}
701da8c4 1137
5160b401 1138=head2 throw_exception
701da8c4 1139
a2531bf2 1140See L<DBIx::Class::Schema/throw_exception>.
701da8c4 1141
1142=cut
1143
1144sub throw_exception {
1145 my $self=shift;
66cab05c 1146 if (ref $self && ref $self->result_source && $self->result_source->schema) {
701da8c4 1147 $self->result_source->schema->throw_exception(@_);
1148 } else {
1149 croak(@_);
1150 }
1151}
1152
33cf6616 1153=head2 id
1154
a2531bf2 1155 my @pk = $row->id;
1156
1157=over
1158
1159=item Arguments: none
1160
1161=item Returns: A list of primary key values
1162
1163=back
1164
33cf6616 1165Returns the primary key(s) for a row. Can't be called as a class method.
f7043881 1166Actually implemented in L<DBIx::Class::PK>
33cf6616 1167
1168=head2 discard_changes
1169
a2531bf2 1170 $row->discard_changes
1171
1172=over
1173
1174=item Arguments: none
1175
1176=item Returns: nothing (updates object in-place)
1177
1178=back
1179
1180Retrieves and sets the row object data from the database, losing any
1181local changes made.
33cf6616 1182
1183This method can also be used to refresh from storage, retrieving any
1184changes made since the row was last read from storage. Actually
f7043881 1185implemented in L<DBIx::Class::PK>
33cf6616 1186
1187=cut
1188
7624b19f 11891;
1190
7624b19f 1191=head1 AUTHORS
1192
daec44b8 1193Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 1194
1195=head1 LICENSE
1196
1197You may distribute this code under the same terms as Perl itself.
1198
1199=cut