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