Fix MC double-object creation (important for e.g. IC::FS which otherwise leaves orpha...
[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/;
1a58752c 7
8use DBIx::Class::Exception;
33dd4e80 9use Scalar::Util ();
9780718f 10use Try::Tiny;
1edd1722 11
0d5d1f12 12###
13### Internal method
14### Do not use
15###
e0cdf2cb 16BEGIN {
17 *MULTICREATE_DEBUG =
18 $ENV{DBIC_MULTICREATE_DEBUG}
19 ? sub () { 1 }
20 : sub () { 0 };
21}
22
aec3eff1 23__PACKAGE__->mk_group_accessors('simple' => qw/_source_handle/);
8c49f629 24
75d07914 25=head1 NAME
7624b19f 26
27DBIx::Class::Row - Basic row methods
28
29=head1 SYNOPSIS
30
31=head1 DESCRIPTION
32
33This class is responsible for defining and doing basic operations on rows
1ea77c14 34derived from L<DBIx::Class::ResultSource> objects.
7624b19f 35
a2531bf2 36Row objects are returned from L<DBIx::Class::ResultSet>s using the
ea36f4e4 37L<create|DBIx::Class::ResultSet/create>, L<find|DBIx::Class::ResultSet/find>,
38L<next|DBIx::Class::ResultSet/next> and L<all|DBIx::Class::ResultSet/all> methods,
39as well as invocations of 'single' (
40L<belongs_to|DBIx::Class::Relationship/belongs_to>,
41L<has_one|DBIx::Class::Relationship/has_one> or
42L<might_have|DBIx::Class::Relationship/might_have>)
43relationship accessors of L<DBIx::Class::Row> objects.
a2531bf2 44
7624b19f 45=head1 METHODS
46
8091aa91 47=head2 new
7624b19f 48
a2531bf2 49 my $row = My::Class->new(\%attrs);
50
51 my $row = $schema->resultset('MySource')->new(\%colsandvalues);
52
53=over
54
55=item Arguments: \%attrs or \%colsandvalues
56
57=item Returns: A Row object
7624b19f 58
a2531bf2 59=back
60
61While you can create a new row object by calling C<new> directly on
62this class, you are better off calling it on a
63L<DBIx::Class::ResultSet> object.
64
65When calling it directly, you will not get a complete, usable row
66object until you pass or set the C<source_handle> attribute, to a
67L<DBIx::Class::ResultSource> instance that is attached to a
68L<DBIx::Class::Schema> with a valid connection.
69
70C<$attrs> is a hashref of column name, value data. It can also contain
71some other attributes such as the C<source_handle>.
7624b19f 72
33dd4e80 73Passing an object, or an arrayref of objects as a value will call
74L<DBIx::Class::Relationship::Base/set_from_related> for you. When
75passed a hashref or an arrayref of hashrefs as the value, these will
76be turned into objects via new_related, and treated as if you had
77passed objects.
78
264f1571 79For a more involved explanation, see L<DBIx::Class::ResultSet/create>.
80
dc5f0ad3 81Please note that if a value is not passed to new, no value will be sent
82in the SQL INSERT call, and the column will therefore assume whatever
83default value was specified in your database. While DBIC will retrieve the
84value of autoincrement columns, it will never make an explicit database
85trip to retrieve default values assigned by the RDBMS. You can explicitly
86request that all values be fetched back from the database by calling
87L</discard_changes>, or you can supply an explicit C<undef> to columns
88with NULL as the default, and save yourself a SELECT.
89
90 CAVEAT:
91
92 The behavior described above will backfire if you use a foreign key column
93 with a database-defined default. If you call the relationship accessor on
94 an object that doesn't have a set value for the FK column, DBIC will throw
95 an exception, as it has no way of knowing the PK of the related object (if
96 there is one).
97
7624b19f 98=cut
99
33dd4e80 100## 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().
101## This only works because DBIC doesnt yet care to check whether the new_related objects have been passed all their mandatory columns
102## When doing the later insert, we need to make sure the PKs are set.
103## using _relationship_data in new and funky ways..
104## check Relationship::CascadeActions and Relationship::Accessor for compat
105## tests!
106
370f2ba2 107sub __new_related_find_or_new_helper {
108 my ($self, $relname, $data) = @_;
68888c09 109
b7ded743 110 my $rsrc = $self->result_source;
111
68888c09 112 # create a mock-object so all new/set_column component overrides will run:
b7ded743 113 my $rel_rs = $rsrc->related_source($relname)->resultset;
68888c09 114 my $new_rel_obj = $rel_rs->new_result($data);
115 my $proc_data = { $new_rel_obj->get_columns };
116
117 if ($self->__their_pk_needs_us($relname)) {
de404241 118 MULTICREATE_DEBUG and warn "MC $self constructing $relname via new_result";
68888c09 119 return $new_rel_obj;
120 }
b7ded743 121 elsif ($rsrc->_pk_depends_on($relname, $proc_data )) {
68888c09 122 if (! keys %$proc_data) {
123 # there is nothing to search for - blind create
124 MULTICREATE_DEBUG and warn "MC $self constructing default-insert $relname";
125 }
126 else {
127 MULTICREATE_DEBUG and warn "MC $self constructing $relname via find_or_new";
128 # this is not *really* find or new, as we don't want to double-new the
129 # data (thus potentially double encoding or whatever)
130 my $exists = $rel_rs->find ($proc_data);
131 return $exists if $exists;
132 }
133 return $new_rel_obj;
370f2ba2 134 }
68888c09 135 else {
b7ded743 136 my $us = $rsrc->source_name;
68888c09 137 $self->throw_exception ("'$us' neither depends nor is depended on by '$relname', something is wrong...");
370f2ba2 138 }
370f2ba2 139}
140
141sub __their_pk_needs_us { # this should maybe be in resultsource.
68888c09 142 my ($self, $relname) = @_;
370f2ba2 143 my $source = $self->result_source;
144 my $reverse = $source->reverse_relationship_info($relname);
145 my $rel_source = $source->related_source($relname);
146 my $us = { $self->get_columns };
147 foreach my $key (keys %$reverse) {
148 # if their primary key depends on us, then we have to
149 # just create a result and we'll fill it out afterwards
6d0ee587 150 return 1 if $rel_source->_pk_depends_on($key, $us);
370f2ba2 151 }
152 return 0;
153}
154
7624b19f 155sub new {
448f820f 156 my ($class, $attrs) = @_;
7624b19f 157 $class = ref $class if ref $class;
04786a4c 158
e60dc79f 159 my $new = {
160 _column_data => {},
161 };
04786a4c 162 bless $new, $class;
163
448f820f 164 if (my $handle = delete $attrs->{-source_handle}) {
165 $new->_source_handle($handle);
166 }
370f2ba2 167
168 my $source;
169 if ($source = delete $attrs->{-result_source}) {
e9fe476b 170 $new->result_source($source);
171 }
a6a280b9 172
fa7a51af 173 if (my $related = delete $attrs->{-cols_from_relations}) {
09e1f723 174 @{$new->{_ignore_at_insert}={}}{@$related} = ();
175 }
176
7624b19f 177 if ($attrs) {
27f01d1f 178 $new->throw_exception("attrs must be a hashref")
179 unless ref($attrs) eq 'HASH';
b6d347e0 180
61a622ee 181 my ($related,$inflated);
8222f722 182
61a622ee 183 foreach my $key (keys %$attrs) {
184 if (ref $attrs->{$key}) {
af2d42c0 185 ## Can we extract this lot to use with update(_or .. ) ?
1a58752c 186 $new->throw_exception("Can't do multi-create without result source")
187 unless $source;
370f2ba2 188 my $info = $source->relationship_info($key);
b82c8a28 189 my $acc_type = $info->{attrs}{accessor} || '';
190 if ($acc_type eq 'single') {
de7c7c53 191 my $rel_obj = delete $attrs->{$key};
33dd4e80 192 if(!Scalar::Util::blessed($rel_obj)) {
370f2ba2 193 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 194 }
2bc3c81e 195
e0cdf2cb 196 if ($rel_obj->in_storage) {
d4fe33d0 197 $new->{_rel_in_storage}{$key} = 1;
e0cdf2cb 198 $new->set_from_related($key, $rel_obj);
199 } else {
09e1f723 200 MULTICREATE_DEBUG and warn "MC $new uninserted $key $rel_obj\n";
e0cdf2cb 201 }
2bc3c81e 202
de7c7c53 203 $related->{$key} = $rel_obj;
61a622ee 204 next;
b82c8a28 205 }
206 elsif ($acc_type eq 'multi' && ref $attrs->{$key} eq 'ARRAY' ) {
2ec8e594 207 my $others = delete $attrs->{$key};
e0cdf2cb 208 my $total = @$others;
209 my @objects;
210 foreach my $idx (0 .. $#$others) {
211 my $rel_obj = $others->[$idx];
2ec8e594 212 if(!Scalar::Util::blessed($rel_obj)) {
370f2ba2 213 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 214 }
2bc3c81e 215
e0cdf2cb 216 if ($rel_obj->in_storage) {
d4fe33d0 217 $rel_obj->throw_exception ('A multi relationship can not be pre-existing when doing multicreate. Something went wrong');
e0cdf2cb 218 } else {
e0cdf2cb 219 MULTICREATE_DEBUG and
09e1f723 220 warn "MC $new uninserted $key $rel_obj (${\($idx+1)} of $total)\n";
e0cdf2cb 221 }
e0cdf2cb 222 push(@objects, $rel_obj);
2ec8e594 223 }
e0cdf2cb 224 $related->{$key} = \@objects;
2ec8e594 225 next;
b82c8a28 226 }
227 elsif ($acc_type eq 'filter') {
33dd4e80 228 ## 'filter' should disappear and get merged in with 'single' above!
2ec8e594 229 my $rel_obj = delete $attrs->{$key};
33dd4e80 230 if(!Scalar::Util::blessed($rel_obj)) {
370f2ba2 231 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 232 }
d4fe33d0 233 if ($rel_obj->in_storage) {
234 $new->{_rel_in_storage}{$key} = 1;
235 }
236 else {
09e1f723 237 MULTICREATE_DEBUG and warn "MC $new uninserted $key $rel_obj";
e0cdf2cb 238 }
33dd4e80 239 $inflated->{$key} = $rel_obj;
61a622ee 240 next;
2ec8e594 241 } elsif ($class->has_column($key)
242 && $class->column_info($key)->{_inflate_info}) {
61a622ee 243 $inflated->{$key} = $attrs->{$key};
244 next;
245 }
246 }
247 $new->throw_exception("No such column $key on $class")
248 unless $class->has_column($key);
b6d347e0 249 $new->store_column($key => $attrs->{$key});
7624b19f 250 }
f90375dd 251
61a622ee 252 $new->{_relationship_data} = $related if $related;
253 $new->{_inflated_column} = $inflated if $inflated;
7624b19f 254 }
04786a4c 255
7624b19f 256 return $new;
257}
258
8091aa91 259=head2 insert
7624b19f 260
a2531bf2 261 $row->insert;
262
263=over
7624b19f 264
a2531bf2 265=item Arguments: none
266
267=item Returns: The Row object
268
269=back
270
271Inserts an object previously created by L</new> into the database if
272it isn't already in there. Returns the object itself. Requires the
273object's result source to be set, or the class to have a
274result_source_instance method. To insert an entirely new row into
275the database, use C<create> (see L<DBIx::Class::ResultSet/create>).
7624b19f 276
e91e756c 277To fetch an uninserted row object, call
278L<new|DBIx::Class::ResultSet/new> on a resultset.
279
264f1571 280This will also insert any uninserted, related objects held inside this
281one, see L<DBIx::Class::ResultSet/create> for more details.
282
7624b19f 283=cut
284
285sub insert {
286 my ($self) = @_;
287 return $self if $self->in_storage;
6aba697f 288 my $source = $self->result_source;
289 $source ||= $self->result_source($self->result_source_instance)
097d3227 290 if $self->can('result_source_instance');
aeb1bf75 291 $self->throw_exception("No result_source set on this object; can't insert")
292 unless $source;
6e399b4f 293
9c6d6d93 294 my $rollback_guard;
295
33dd4e80 296 # Check if we stored uninserted relobjs here in new()
b6d347e0 297 my %related_stuff = (%{$self->{_relationship_data} || {}},
33dd4e80 298 %{$self->{_inflated_column} || {}});
9c6d6d93 299
d4fe33d0 300 # insert what needs to be inserted before us
301 my %pre_insert;
302 for my $relname (keys %related_stuff) {
303 my $rel_obj = $related_stuff{$relname};
9c6d6d93 304
d4fe33d0 305 if (! $self->{_rel_in_storage}{$relname}) {
306 next unless (Scalar::Util::blessed($rel_obj)
307 && $rel_obj->isa('DBIx::Class::Row'));
a8c98174 308
d4fe33d0 309 next unless $source->_pk_depends_on(
310 $relname, { $rel_obj->get_columns }
311 );
a8c98174 312
d4fe33d0 313 # The guard will save us if we blow out of this scope via die
314 $rollback_guard ||= $source->storage->txn_scope_guard;
9c6d6d93 315
de404241 316 MULTICREATE_DEBUG and warn "MC $self pre-reconstructing $relname $rel_obj\n";
e0cdf2cb 317
380d34f5 318 my $them = { %{$rel_obj->{_relationship_data} || {} }, $rel_obj->get_columns };
68888c09 319 my $existing;
320
321 # if there are no keys - nothing to search for
322 if (keys %$them and $existing = $self->result_source
323 ->related_source($relname)
324 ->resultset
325 ->find($them)
326 ) {
327 %{$rel_obj} = %{$existing};
328 }
329 else {
330 $rel_obj->insert;
331 }
d4fe33d0 332
d4fe33d0 333 $self->{_rel_in_storage}{$relname} = 1;
33dd4e80 334 }
d4fe33d0 335
336 $self->set_from_related($relname, $rel_obj);
337 delete $related_stuff{$relname};
338 }
339
340 # start a transaction here if not started yet and there is more stuff
341 # to insert after us
342 if (keys %related_stuff) {
343 $rollback_guard ||= $source->storage->txn_scope_guard
33dd4e80 344 }
6e399b4f 345
1e45aa87 346 ## PK::Auto
347 my %auto_pri;
348 my $auto_idx = 0;
349 for ($self->primary_columns) {
350 if (
351 not defined $self->get_column($_)
352 ||
353 (ref($self->get_column($_)) eq 'SCALAR')
354 ) {
355 my $col_info = $source->column_info($_);
356 $auto_pri{$_} = $auto_idx++ unless $col_info->{auto_nextval}; # auto_nextval's are pre-fetched in the storage
357 }
358 }
359
09e1f723 360 MULTICREATE_DEBUG and do {
361 no warnings 'uninitialized';
362 warn "MC $self inserting (".join(', ', $self->get_columns).")\n";
363 };
1e45aa87 364 my $updated_cols = $source->storage->insert(
365 $source,
366 { $self->get_columns },
227d8366 367 (keys %auto_pri) && $source->storage->_supports_insert_returning
734868da 368 ? { returning => [ sort { $auto_pri{$a} <=> $auto_pri{$b} } keys %auto_pri ] }
1e45aa87 369 : ()
370 ,
371 );
372
645de900 373 foreach my $col (keys %$updated_cols) {
374 $self->store_column($col, $updated_cols->{$col});
1e45aa87 375 delete $auto_pri{$col};
645de900 376 }
ac8e89d7 377
1e45aa87 378 if (keys %auto_pri) {
379 my @missing = sort { $auto_pri{$a} <=> $auto_pri{$b} } keys %auto_pri;
380 MULTICREATE_DEBUG and warn "MC $self fetching missing PKs ".join(', ', @missing )."\n";
ac8e89d7 381 my $storage = $self->result_source->storage;
382 $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" )
383 unless $storage->can('last_insert_id');
1e45aa87 384 my @ids = $storage->last_insert_id($self->result_source, @missing);
3fda409f 385 $self->throw_exception( "Can't get last insert id" )
1e45aa87 386 unless (@ids == @missing);
387 $self->store_column($missing[$_] => $ids[$_]) for 0 .. $#missing;
ac8e89d7 388 }
33dd4e80 389
370f2ba2 390 $self->{_dirty_columns} = {};
391 $self->{related_resultsets} = {};
392
d4fe33d0 393 foreach my $relname (keys %related_stuff) {
31c3800e 394 next unless $source->has_relationship ($relname);
395
396 my @cands = ref $related_stuff{$relname} eq 'ARRAY'
397 ? @{$related_stuff{$relname}}
398 : $related_stuff{$relname}
399 ;
d4fe33d0 400
31c3800e 401 if (@cands
402 && Scalar::Util::blessed($cands[0])
403 && $cands[0]->isa('DBIx::Class::Row')
404 ) {
d4fe33d0 405 my $reverse = $source->reverse_relationship_info($relname);
406 foreach my $obj (@cands) {
407 $obj->set_from_related($_, $self) for keys %$reverse;
68888c09 408 if ($self->__their_pk_needs_us($relname)) {
d4fe33d0 409 if (exists $self->{_ignore_at_insert}{$relname}) {
410 MULTICREATE_DEBUG and warn "MC $self skipping post-insert on $relname";
65ee2b31 411 }
412 else {
413 MULTICREATE_DEBUG and warn "MC $self inserting $relname $obj";
414 $obj->insert;
370f2ba2 415 }
d4fe33d0 416 } else {
417 MULTICREATE_DEBUG and warn "MC $self post-inserting $obj";
418 $obj->insert();
8222f722 419 }
33dd4e80 420 }
421 }
422 }
33dd4e80 423
7624b19f 424 $self->in_storage(1);
d4fe33d0 425 delete $self->{_orig_ident};
426 delete $self->{_ignore_at_insert};
427 $rollback_guard->commit if $rollback_guard;
428
7624b19f 429 return $self;
430}
431
8091aa91 432=head2 in_storage
7624b19f 433
a2531bf2 434 $row->in_storage; # Get value
435 $row->in_storage(1); # Set value
436
437=over
438
439=item Arguments: none or 1|0
440
441=item Returns: 1|0
442
443=back
7624b19f 444
e91e756c 445Indicates whether the object exists as a row in the database or
446not. This is set to true when L<DBIx::Class::ResultSet/find>,
447L<DBIx::Class::ResultSet/create> or L<DBIx::Class::ResultSet/insert>
b6d347e0 448are used.
e91e756c 449
450Creating a row object using L<DBIx::Class::ResultSet/new>, or calling
451L</delete> on one, sets it to false.
7624b19f 452
453=cut
454
455sub in_storage {
456 my ($self, $val) = @_;
457 $self->{_in_storage} = $val if @_ > 1;
63bb9738 458 return $self->{_in_storage} ? 1 : 0;
7624b19f 459}
460
8091aa91 461=head2 update
7624b19f 462
a2531bf2 463 $row->update(\%columns?)
464
465=over
7624b19f 466
a2531bf2 467=item Arguments: none or a hashref
7624b19f 468
a2531bf2 469=item Returns: The Row object
470
471=back
472
473Throws an exception if the row object is not yet in the database,
474according to L</in_storage>.
475
476This method issues an SQL UPDATE query to commit any changes to the
d6988be8 477object to the database if required (see L</get_dirty_columns>).
478It throws an exception if a proper WHERE clause uniquely identifying
479the database row can not be constructed (see
480L<significance of primary keys|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
481for more details).
a2531bf2 482
0d0fcdbf 483Also takes an optional hashref of C<< column_name => value >> pairs
a2531bf2 484to update on the object first. Be aware that the hashref will be
485passed to C<set_inflated_columns>, which might edit it in place, so
486don't rely on it being the same after a call to C<update>. If you
487need to preserve the hashref, it is sufficient to pass a shallow copy
488to C<update>, e.g. ( { %{ $href } } )
d5d833d9 489
05d1bc9c 490If the values passed or any of the column values set on the object
48580715 491contain scalar references, e.g.:
05d1bc9c 492
a2531bf2 493 $row->last_modified(\'NOW()');
05d1bc9c 494 # OR
a2531bf2 495 $row->update({ last_modified => \'NOW()' });
05d1bc9c 496
497The update will pass the values verbatim into SQL. (See
498L<SQL::Abstract> docs). The values in your Row object will NOT change
499as a result of the update call, if you want the object to be updated
500with the actual values from the database, call L</discard_changes>
501after the update.
502
a2531bf2 503 $row->update()->discard_changes();
504
505To determine before calling this method, which column values have
506changed and will be updated, call L</get_dirty_columns>.
507
508To check if any columns will be updated, call L</is_changed>.
509
510To force a column to be updated, call L</make_column_dirty> before
511this method.
05d1bc9c 512
7624b19f 513=cut
514
515sub update {
516 my ($self, $upd) = @_;
cf856357 517
97a50975 518 my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
519
bacf6f12 520 $self->set_inflated_columns($upd) if $upd;
5a9e0e60 521 my %to_update = $self->get_dirty_columns;
522 return $self unless keys %to_update;
de5ce481 523
524 $self->throw_exception( "Not in database" ) unless $self->in_storage;
525
ad3f2296 526 $self->throw_exception('Unable to update a row with incomplete or no identity')
527 if ! keys %$ident_cond;
528
88cb6a1d 529 my $rows = $self->result_source->storage->update(
cf856357 530 $self->result_source, \%to_update, $ident_cond
531 );
7624b19f 532 if ($rows == 0) {
701da8c4 533 $self->throw_exception( "Can't update ${self}: row not found" );
7624b19f 534 } elsif ($rows > 1) {
701da8c4 535 $self->throw_exception("Can't update ${self}: updated more than one row");
7624b19f 536 }
537 $self->{_dirty_columns} = {};
64acc2bc 538 $self->{related_resultsets} = {};
cf856357 539 delete $self->{_orig_ident};
7624b19f 540 return $self;
541}
542
8091aa91 543=head2 delete
7624b19f 544
a2531bf2 545 $row->delete
546
547=over
548
549=item Arguments: none
7624b19f 550
a2531bf2 551=item Returns: The Row object
552
553=back
554
555Throws an exception if the object is not in the database according to
d6988be8 556L</in_storage>. Also throws an exception if a proper WHERE clause
557uniquely identifying the database row can not be constructed (see
558L<significance of primary keys|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
559for more details).
a2531bf2 560
561The object is still perfectly usable, but L</in_storage> will
ea36f4e4 562now return 0 and the object must be reinserted using L</insert>
b6d347e0 563before it can be used to L</update> the row again.
a2531bf2 564
565If you delete an object in a class with a C<has_many> relationship, an
566attempt is made to delete all the related objects as well. To turn
567this behaviour off, pass C<< cascade_delete => 0 >> in the C<$attr>
568hashref of the relationship, see L<DBIx::Class::Relationship>. Any
569database-level cascade or restrict will take precedence over a
281e677e 570DBIx-Class-based cascading delete, since DBIx-Class B<deletes the
571main row first> and only then attempts to delete any remaining related
572rows.
a2531bf2 573
b1d16ffd 574If you delete an object within a txn_do() (see L<DBIx::Class::Storage/txn_do>)
575and the transaction subsequently fails, the row object will remain marked as
576not being in storage. If you know for a fact that the object is still in
577storage (i.e. by inspecting the cause of the transaction's failure), you can
578use C<< $obj->in_storage(1) >> to restore consistency between the object and
579the database. This would allow a subsequent C<< $obj->delete >> to work
580as expected.
581
a2531bf2 582See also L<DBIx::Class::ResultSet/delete>.
7624b19f 583
584=cut
585
586sub delete {
587 my $self = shift;
588 if (ref $self) {
701da8c4 589 $self->throw_exception( "Not in database" ) unless $self->in_storage;
cf856357 590
728e60a3 591 my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
cf856357 592 $self->throw_exception('Unable to delete a row with incomplete or no identity')
4b12b3c2 593 if ! keys %$ident_cond;
cf856357 594
88cb6a1d 595 $self->result_source->storage->delete(
cf856357 596 $self->result_source, $ident_cond
597 );
598
599 delete $self->{_orig_ident};
7624b19f 600 $self->in_storage(undef);
cf856357 601 }
602 else {
701da8c4 603 $self->throw_exception("Can't do class delete without a ResultSource instance")
097d3227 604 unless $self->can('result_source_instance');
aeb1bf75 605 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
606 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
097d3227 607 $self->result_source_instance->resultset->search(@_)->delete;
7624b19f 608 }
609 return $self;
610}
611
8091aa91 612=head2 get_column
7624b19f 613
a2531bf2 614 my $val = $row->get_column($col);
615
616=over
617
618=item Arguments: $columnname
619
620=item Returns: The value of the column
621
622=back
623
624Throws an exception if the column name given doesn't exist according
625to L</has_column>.
7624b19f 626
e91e756c 627Returns a raw column value from the row object, if it has already
628been fetched from the database or set by an accessor.
629
630If an L<inflated value|DBIx::Class::InflateColumn> has been set, it
631will be deflated and returned.
7624b19f 632
ea36f4e4 633Note that if you used the C<columns> or the C<select/as>
634L<search attributes|DBIx::Class::ResultSet/ATTRIBUTES> on the resultset from
635which C<$row> was derived, and B<did not include> C<$columnname> in the list,
636this method will return C<undef> even if the database contains some value.
637
a2531bf2 638To retrieve all loaded column values as a hash, use L</get_columns>.
639
7624b19f 640=cut
641
642sub get_column {
643 my ($self, $column) = @_;
701da8c4 644 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
aeb1bf75 645 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
61a622ee 646 if (exists $self->{_inflated_column}{$column}) {
647 return $self->store_column($column,
b6d347e0 648 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
61a622ee 649 }
701da8c4 650 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
7624b19f 651 return undef;
652}
653
9b83fccd 654=head2 has_column_loaded
655
a2531bf2 656 if ( $row->has_column_loaded($col) ) {
9b83fccd 657 print "$col has been loaded from db";
658 }
659
a2531bf2 660=over
661
662=item Arguments: $columnname
663
664=item Returns: 0|1
665
666=back
667
9b83fccd 668Returns a true value if the column value has been loaded from the
669database (or set locally).
670
671=cut
672
def81720 673sub has_column_loaded {
674 my ($self, $column) = @_;
675 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
61a622ee 676 return 1 if exists $self->{_inflated_column}{$column};
aeb1bf75 677 return exists $self->{_column_data}{$column};
def81720 678}
679
8091aa91 680=head2 get_columns
076a6864 681
a2531bf2 682 my %data = $row->get_columns;
683
684=over
685
686=item Arguments: none
076a6864 687
a2531bf2 688=item Returns: A hash of columnname, value pairs.
689
690=back
691
692Returns all loaded column data as a hash, containing raw values. To
693get just one value for a particular column, use L</get_column>.
076a6864 694
c0a171bf 695See L</get_inflated_columns> to get the inflated values.
696
076a6864 697=cut
698
699sub get_columns {
700 my $self = shift;
61a622ee 701 if (exists $self->{_inflated_column}) {
702 foreach my $col (keys %{$self->{_inflated_column}}) {
703 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
c4a30d56 704 unless exists $self->{_column_data}{$col};
61a622ee 705 }
706 }
cb5f2eea 707 return %{$self->{_column_data}};
d7156e50 708}
709
710=head2 get_dirty_columns
711
a2531bf2 712 my %data = $row->get_dirty_columns;
713
714=over
715
716=item Arguments: none
d7156e50 717
a2531bf2 718=item Returns: A hash of column, value pairs
719
720=back
721
722Only returns the column, value pairs for those columns that have been
723changed on this object since the last L</update> or L</insert> call.
724
725See L</get_columns> to fetch all column/value pairs.
d7156e50 726
727=cut
728
729sub get_dirty_columns {
730 my $self = shift;
731 return map { $_ => $self->{_column_data}{$_} }
732 keys %{$self->{_dirty_columns}};
076a6864 733}
734
6dbea98e 735=head2 make_column_dirty
736
a2531bf2 737 $row->make_column_dirty($col)
738
739=over
740
741=item Arguments: $columnname
742
743=item Returns: undefined
744
745=back
746
747Throws an exception if the column does not exist.
748
749Marks a column as having been changed regardless of whether it has
b6d347e0 750really changed.
6dbea98e 751
752=cut
753sub make_column_dirty {
754 my ($self, $column) = @_;
755
756 $self->throw_exception( "No such column '${column}'" )
757 unless exists $self->{_column_data}{$column} || $self->has_column($column);
497d874a 758
b6d347e0 759 # the entire clean/dirty code relies on exists, not on true/false
497d874a 760 return 1 if exists $self->{_dirty_columns}{$column};
761
6dbea98e 762 $self->{_dirty_columns}{$column} = 1;
497d874a 763
764 # if we are just now making the column dirty, and if there is an inflated
765 # value, force it over the deflated one
766 if (exists $self->{_inflated_column}{$column}) {
767 $self->store_column($column,
768 $self->_deflated_column(
769 $column, $self->{_inflated_column}{$column}
770 )
771 );
772 }
6dbea98e 773}
774
ba4a6453 775=head2 get_inflated_columns
776
e91e756c 777 my %inflated_data = $obj->get_inflated_columns;
ba4a6453 778
a2531bf2 779=over
780
781=item Arguments: none
782
783=item Returns: A hash of column, object|value pairs
784
785=back
786
787Returns a hash of all column keys and associated values. Values for any
788columns set to use inflation will be inflated and returns as objects.
789
790See L</get_columns> to get the uninflated values.
791
792See L<DBIx::Class::InflateColumn> for how to setup inflation.
ba4a6453 793
794=cut
795
796sub get_inflated_columns {
797 my $self = shift;
d61b2132 798
799 my %loaded_colinfo = (map
800 { $_ => $self->column_info($_) }
801 (grep { $self->has_column_loaded($_) } $self->columns)
802 );
803
804 my %inflated;
805 for my $col (keys %loaded_colinfo) {
806 if (exists $loaded_colinfo{$col}{accessor}) {
807 my $acc = $loaded_colinfo{$col}{accessor};
9c042209 808 $inflated{$col} = $self->$acc if defined $acc;
d61b2132 809 }
810 else {
811 $inflated{$col} = $self->$col;
812 }
813 }
814
815 # return all loaded columns with the inflations overlayed on top
816 return ($self->get_columns, %inflated);
ba4a6453 817}
818
ca8a1270 819sub _is_column_numeric {
0bb1a52f 820 my ($self, $column) = @_;
821 my $colinfo = $self->column_info ($column);
822
823 # cache for speed (the object may *not* have a resultsource instance)
824 if (not defined $colinfo->{is_numeric} && $self->_source_handle) {
825 $colinfo->{is_numeric} =
826 $self->result_source->schema->storage->is_datatype_numeric ($colinfo->{data_type})
827 ? 1
828 : 0
829 ;
830 }
831
832 return $colinfo->{is_numeric};
833}
834
8091aa91 835=head2 set_column
7624b19f 836
a2531bf2 837 $row->set_column($col => $val);
838
839=over
840
841=item Arguments: $columnname, $value
842
843=item Returns: $value
844
845=back
7624b19f 846
e91e756c 847Sets a raw column value. If the new value is different from the old one,
a2531bf2 848the column is marked as dirty for when you next call L</update>.
7624b19f 849
ea36f4e4 850If passed an object or reference as a value, this method will happily
851attempt to store it, and a later L</insert> or L</update> will try and
a2531bf2 852stringify/numify as appropriate. To set an object to be deflated
853instead, see L</set_inflated_columns>.
e91e756c 854
7624b19f 855=cut
856
857sub set_column {
1d0057bd 858 my ($self, $column, $new_value) = @_;
859
cf856357 860 # if we can't get an ident condition on first try - mark the object as unidentifiable
9780718f 861 $self->{_orig_ident} ||= (try { $self->ident_condition }) || {};
1d0057bd 862
cf856357 863 my $old_value = $self->get_column($column);
b236052f 864 $new_value = $self->store_column($column, $new_value);
8f9eff75 865
cde96798 866 my $dirty =
867 $self->{_dirty_columns}{$column}
868 ||
869 $self->in_storage # no point tracking dirtyness on uninserted data
870 ? ! $self->_eq_column_values ($column, $old_value, $new_value)
871 : 1
872 ;
8f9eff75 873
cde96798 874 # FIXME sadly the update code just checks for keys, not for their value
8f9eff75 875 $self->{_dirty_columns}{$column} = 1 if $dirty;
e60dc79f 876
877 # XXX clear out the relation cache for this column
878 delete $self->{related_resultsets}{$column};
879
1d0057bd 880 return $new_value;
7624b19f 881}
882
cde96798 883sub _eq_column_values {
884 my ($self, $col, $old, $new) = @_;
885
886 if (defined $old xor defined $new) {
887 return 0;
888 }
889 elsif (not defined $old) { # both undef
890 return 1;
891 }
892 elsif ($old eq $new) {
893 return 1;
894 }
895 elsif ($self->_is_column_numeric($col)) { # do a numeric comparison if datatype allows it
896 return $old == $new;
897 }
898 else {
899 return 0;
900 }
901}
902
8091aa91 903=head2 set_columns
076a6864 904
a2531bf2 905 $row->set_columns({ $col => $val, ... });
906
b6d347e0 907=over
076a6864 908
a2531bf2 909=item Arguments: \%columndata
910
911=item Returns: The Row object
912
913=back
914
915Sets multiple column, raw value pairs at once.
916
917Works as L</set_column>.
076a6864 918
919=cut
920
921sub set_columns {
922 my ($self,$data) = @_;
a2ca474b 923 foreach my $col (keys %$data) {
924 $self->set_column($col,$data->{$col});
076a6864 925 }
c01ab172 926 return $self;
076a6864 927}
928
bacf6f12 929=head2 set_inflated_columns
930
a2531bf2 931 $row->set_inflated_columns({ $col => $val, $relname => $obj, ... });
932
933=over
934
935=item Arguments: \%columndata
936
937=item Returns: The Row object
938
939=back
940
941Sets more than one column value at once. Any inflated values are
b6d347e0 942deflated and the raw values stored.
bacf6f12 943
a2531bf2 944Any related values passed as Row objects, using the relation name as a
945key, are reduced to the appropriate foreign key values and stored. If
946instead of related row objects, a hashref of column, value data is
947passed, will create the related object first then store.
948
949Will even accept arrayrefs of data as a value to a
950L<DBIx::Class::Relationship/has_many> key, and create the related
951objects if necessary.
952
c1300297 953Be aware that the input hashref might be edited in place, so don't rely
a2531bf2 954on it being the same after a call to C<set_inflated_columns>. If you
955need to preserve the hashref, it is sufficient to pass a shallow copy
956to C<set_inflated_columns>, e.g. ( { %{ $href } } )
957
958See also L<DBIx::Class::Relationship::Base/set_from_related>.
bacf6f12 959
960=cut
961
962sub set_inflated_columns {
963 my ( $self, $upd ) = @_;
964 foreach my $key (keys %$upd) {
965 if (ref $upd->{$key}) {
966 my $info = $self->relationship_info($key);
b82c8a28 967 my $acc_type = $info->{attrs}{accessor} || '';
968 if ($acc_type eq 'single') {
bacf6f12 969 my $rel = delete $upd->{$key};
970 $self->set_from_related($key => $rel);
a7be8807 971 $self->{_relationship_data}{$key} = $rel;
bacf6f12 972 }
b82c8a28 973 elsif ($acc_type eq 'multi') {
974 $self->throw_exception(
975 "Recursive update is not supported over relationships of type '$acc_type' ($key)"
976 );
977 }
978 elsif ($self->has_column($key) && exists $self->column_info($key)->{_inflate_info}) {
a7be8807 979 $self->set_inflated_column($key, delete $upd->{$key});
bacf6f12 980 }
981 }
982 }
b6d347e0 983 $self->set_columns($upd);
bacf6f12 984}
985
8091aa91 986=head2 copy
076a6864 987
988 my $copy = $orig->copy({ change => $to, ... });
989
a2531bf2 990=over
991
992=item Arguments: \%replacementdata
993
994=item Returns: The Row object copy
995
996=back
997
998Inserts a new row into the database, as a copy of the original
999object. If a hashref of replacement data is supplied, these will take
ce0893e0 1000precedence over data in the original. Also any columns which have
1001the L<column info attribute|DBIx::Class::ResultSource/add_columns>
1002C<< is_auto_increment => 1 >> are explicitly removed before the copy,
1003so that the database can insert its own autoincremented values into
1004the new object.
a2531bf2 1005
f928c965 1006Relationships will be followed by the copy procedure B<only> if the
48580715 1007relationship specifies a true value for its
f928c965 1008L<cascade_copy|DBIx::Class::Relationship::Base> attribute. C<cascade_copy>
1009is set by default on C<has_many> relationships and unset on all others.
076a6864 1010
1011=cut
1012
c01ab172 1013sub copy {
1014 my ($self, $changes) = @_;
333cce60 1015 $changes ||= {};
fde6e28e 1016 my $col_data = { %{$self->{_column_data}} };
1017 foreach my $col (keys %$col_data) {
1018 delete $col_data->{$col}
1019 if $self->result_source->column_info($col)->{is_auto_increment};
1020 }
04786a4c 1021
1022 my $new = { _column_data => $col_data };
1023 bless $new, ref $self;
1024
83419ec6 1025 $new->result_source($self->result_source);
bacf6f12 1026 $new->set_inflated_columns($changes);
333cce60 1027 $new->insert;
35688220 1028
b6d347e0 1029 # Its possible we'll have 2 relations to the same Source. We need to make
48580715 1030 # sure we don't try to insert the same row twice else we'll violate unique
35688220 1031 # constraints
1032 my $rels_copied = {};
1033
333cce60 1034 foreach my $rel ($self->result_source->relationships) {
1035 my $rel_info = $self->result_source->relationship_info($rel);
35688220 1036
1037 next unless $rel_info->{attrs}{cascade_copy};
b6d347e0 1038
6d0ee587 1039 my $resolved = $self->result_source->_resolve_condition(
35688220 1040 $rel_info->{cond}, $rel, $new
1041 );
1042
1043 my $copied = $rels_copied->{ $rel_info->{source} } ||= {};
1044 foreach my $related ($self->search_related($rel)) {
1045 my $id_str = join("\0", $related->id);
1046 next if $copied->{$id_str};
1047 $copied->{$id_str} = 1;
1048 my $rel_copy = $related->copy($resolved);
333cce60 1049 }
b6d347e0 1050
333cce60 1051 }
2c4c67b6 1052 return $new;
c01ab172 1053}
1054
8091aa91 1055=head2 store_column
7624b19f 1056
a2531bf2 1057 $row->store_column($col => $val);
7624b19f 1058
a2531bf2 1059=over
1060
1061=item Arguments: $columnname, $value
1062
ea36f4e4 1063=item Returns: The value sent to storage
a2531bf2 1064
1065=back
1066
1067Set a raw value for a column without marking it as changed. This
1068method is used internally by L</set_column> which you should probably
1069be using.
1070
1071This is the lowest level at which data is set on a row object,
1072extend this method to catch all data setting methods.
7624b19f 1073
1074=cut
1075
1076sub store_column {
1077 my ($self, $column, $value) = @_;
75d07914 1078 $self->throw_exception( "No such column '${column}'" )
d7156e50 1079 unless exists $self->{_column_data}{$column} || $self->has_column($column);
75d07914 1080 $self->throw_exception( "set_column called for ${column} without value" )
7624b19f 1081 if @_ < 3;
1082 return $self->{_column_data}{$column} = $value;
1083}
1084
b52e9bf8 1085=head2 inflate_result
1086
c01ab172 1087 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 1088
a2531bf2 1089=over
1090
d4a20f38 1091=item Arguments: $result_source, \%columndata, \%prefetcheddata
a2531bf2 1092
1093=item Returns: A Row object
1094
1095=back
1096
1097All L<DBIx::Class::ResultSet> methods that retrieve data from the
1098database and turn it into row objects call this method.
1099
1100Extend this method in your Result classes to hook into this process,
1101for example to rebless the result into a different class.
1102
1103Reblessing can also be done more easily by setting C<result_class> in
1104your Result class. See L<DBIx::Class::ResultSource/result_class>.
b52e9bf8 1105
db2b2eb6 1106Different types of results can also be created from a particular
1107L<DBIx::Class::ResultSet>, see L<DBIx::Class::ResultSet/result_class>.
1108
b52e9bf8 1109=cut
1110
1111sub inflate_result {
d4a20f38 1112 my ($class, $source, $me, $prefetch) = @_;
1113
aec3eff1 1114 my ($source_handle) = $source;
1115
1116 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
13d06949 1117 $source = $source_handle->resolve
1118 }
1119 else {
1120 $source_handle = $source->handle
aec3eff1 1121 }
1122
04786a4c 1123 my $new = {
aec3eff1 1124 _source_handle => $source_handle,
04786a4c 1125 _column_data => $me,
04786a4c 1126 };
1127 bless $new, (ref $class || $class);
1128
64acc2bc 1129 foreach my $pre (keys %{$prefetch||{}}) {
35c77aa3 1130
13d06949 1131 my $pre_source = $source->related_source($pre)
1132 or $class->throw_exception("Can't prefetch non-existent relationship ${pre}");
35c77aa3 1133
13d06949 1134 my $accessor = $source->relationship_info($pre)->{attrs}{accessor}
1135 or $class->throw_exception("No accessor for prefetched $pre");
35c77aa3 1136
13d06949 1137 my @pre_vals;
1138 if (ref $prefetch->{$pre}[0] eq 'ARRAY') {
1139 @pre_vals = @{$prefetch->{$pre}};
1140 }
1141 elsif ($accessor eq 'multi') {
1142 $class->throw_exception("Implicit prefetch (via select/columns) not supported with accessor 'multi'");
1143 }
1144 else {
1145 @pre_vals = $prefetch->{$pre};
1146 }
1147
1148 my @pre_objects;
1149 for my $me_pref (@pre_vals) {
1150
1151 # FIXME - this should not be necessary
35c77aa3 1152 # the collapser currently *could* return bogus elements with all
1153 # columns set to undef
1154 my $has_def;
1155 for (values %{$me_pref->[0]}) {
1156 if (defined $_) {
1157 $has_def++;
1158 last;
1159 }
a86b1efe 1160 }
35c77aa3 1161 next unless $has_def;
1162
1163 push @pre_objects, $pre_source->result_class->inflate_result(
1164 $pre_source, @$me_pref
1165 );
13d06949 1166 }
35c77aa3 1167
13d06949 1168 if ($accessor eq 'single') {
1169 $new->{_relationship_data}{$pre} = $pre_objects[0];
b52e9bf8 1170 }
13d06949 1171 elsif ($accessor eq 'filter') {
1172 $new->{_inflated_column}{$pre} = $pre_objects[0];
1173 }
1174
1175 $new->related_resultset($pre)->set_cache(\@pre_objects);
b52e9bf8 1176 }
35c77aa3 1177
1178 $new->in_storage (1);
7624b19f 1179 return $new;
1180}
1181
9b465d00 1182=head2 update_or_insert
7624b19f 1183
a2531bf2 1184 $row->update_or_insert
1185
1186=over
7624b19f 1187
a2531bf2 1188=item Arguments: none
1189
1190=item Returns: Result of update or insert operation
1191
1192=back
1193
1194L</Update>s the object if it's already in the database, according to
1195L</in_storage>, else L</insert>s it.
7624b19f 1196
9b83fccd 1197=head2 insert_or_update
1198
1199 $obj->insert_or_update
1200
1201Alias for L</update_or_insert>
1202
7624b19f 1203=cut
1204
370f2ba2 1205sub insert_or_update { shift->update_or_insert(@_) }
1206
9b465d00 1207sub update_or_insert {
7624b19f 1208 my $self = shift;
1209 return ($self->in_storage ? $self->update : $self->insert);
1210}
1211
8091aa91 1212=head2 is_changed
7624b19f 1213
a2531bf2 1214 my @changed_col_names = $row->is_changed();
1215 if ($row->is_changed()) { ... }
1216
1217=over
7624b19f 1218
a2531bf2 1219=item Arguments: none
1220
1221=item Returns: 0|1 or @columnnames
1222
1223=back
1224
1225In list context returns a list of columns with uncommited changes, or
9b83fccd 1226in scalar context returns a true value if there are uncommitted
1227changes.
1228
7624b19f 1229=cut
1230
1231sub is_changed {
1232 return keys %{shift->{_dirty_columns} || {}};
1233}
228dbcb4 1234
1235=head2 is_column_changed
1236
a2531bf2 1237 if ($row->is_column_changed('col')) { ... }
1238
1239=over
1240
1241=item Arguments: $columname
1242
1243=item Returns: 0|1
1244
1245=back
228dbcb4 1246
9b83fccd 1247Returns a true value if the column has uncommitted changes.
1248
228dbcb4 1249=cut
1250
1251sub is_column_changed {
1252 my( $self, $col ) = @_;
1253 return exists $self->{_dirty_columns}->{$col};
1254}
7624b19f 1255
097d3227 1256=head2 result_source
1257
a2531bf2 1258 my $resultsource = $row->result_source;
1259
1260=over
1261
1262=item Arguments: none
097d3227 1263
a2531bf2 1264=item Returns: a ResultSource instance
1265
1266=back
1267
1268Accessor to the L<DBIx::Class::ResultSource> this object was created from.
87c4e602 1269
aec3eff1 1270=cut
1271
1272sub result_source {
1273 my $self = shift;
1274
1275 if (@_) {
1276 $self->_source_handle($_[0]->handle);
1277 } else {
1278 $self->_source_handle->resolve;
1279 }
1280}
1281
9b83fccd 1282=head2 register_column
27f01d1f 1283
9b83fccd 1284 $column_info = { .... };
1285 $class->register_column($column_name, $column_info);
27f01d1f 1286
a2531bf2 1287=over
1288
1289=item Arguments: $columnname, \%columninfo
1290
1291=item Returns: undefined
1292
1293=back
1294
9b83fccd 1295Registers a column on the class. If the column_info has an 'accessor'
1296key, creates an accessor named after the value if defined; if there is
1297no such key, creates an accessor with the same name as the column
1f23a877 1298
9b83fccd 1299The column_info attributes are described in
1300L<DBIx::Class::ResultSource/add_columns>
1f23a877 1301
097d3227 1302=cut
1303
1f23a877 1304sub register_column {
1305 my ($class, $col, $info) = @_;
91b0fbd7 1306 my $acc = $col;
1307 if (exists $info->{accessor}) {
1308 return unless defined $info->{accessor};
1309 $acc = [ $info->{accessor}, $col ];
1310 }
1311 $class->mk_group_accessors('column' => $acc);
1f23a877 1312}
1313
a2531bf2 1314=head2 get_from_storage
1315
1316 my $copy = $row->get_from_storage($attrs)
1317
1318=over
b9b4e52f 1319
a2531bf2 1320=item Arguments: \%attrs
b9b4e52f 1321
a2531bf2 1322=item Returns: A Row object
1323
1324=back
1325
1326Fetches a fresh copy of the Row object from the database and returns it.
d6988be8 1327Throws an exception if a proper WHERE clause identifying the database row
1328can not be constructed (i.e. if the original object does not contain its
1329entire
1330 L<primary key|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
1331). If passed the \%attrs argument, will first apply these attributes to
a2531bf2 1332the resultset used to find the row.
1333
1334This copy can then be used to compare to an existing row object, to
1335determine if any changes have been made in the database since it was
1336created.
1337
1338To just update your Row object with any latest changes from the
1339database, use L</discard_changes> instead.
1340
1341The \%attrs argument should be compatible with
1342L<DBIx::Class::ResultSet/ATTRIBUTES>.
7e38d850 1343
b9b4e52f 1344=cut
1345
a737512c 1346sub get_from_storage {
b9b4e52f 1347 my $self = shift @_;
7e38d850 1348 my $attrs = shift @_;
7e38d850 1349 my $resultset = $self->result_source->resultset;
b6d347e0 1350
7e38d850 1351 if(defined $attrs) {
bbd107cf 1352 $resultset = $resultset->search(undef, $attrs);
7e38d850 1353 }
b6d347e0 1354
cf856357 1355 my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
1356
1357 $self->throw_exception('Unable to requery a row with incomplete or no identity')
1358 if ! keys %$ident_cond;
1359
1360 return $resultset->find($ident_cond);
b9b4e52f 1361}
701da8c4 1362
bbd107cf 1363=head2 discard_changes ($attrs)
1364
1365Re-selects the row from the database, losing any changes that had
d6988be8 1366been made. Throws an exception if a proper WHERE clause identifying
1367the database row can not be constructed (i.e. if the original object
1368does not contain its entire
1369L<primary key|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
1370).
bbd107cf 1371
1372This method can also be used to refresh from storage, retrieving any
1373changes made since the row was last read from storage.
1374
1375$attrs is expected to be a hashref of attributes suitable for passing as the
1376second argument to $resultset->search($cond, $attrs);
1377
1378=cut
1379
1380sub discard_changes {
1381 my ($self, $attrs) = @_;
bbd107cf 1382 return unless $self->in_storage; # Don't reload if we aren't real!
1383
1384 # add a replication default to read from the master only
1385 $attrs = { force_pool => 'master', %{$attrs||{}} };
1386
1387 if( my $current_storage = $self->get_from_storage($attrs)) {
1388
1389 # Set $self to the current.
1390 %$self = %$current_storage;
1391
1392 # Avoid a possible infinite loop with
1393 # sub DESTROY { $_[0]->discard_changes }
1394 bless $current_storage, 'Do::Not::Exist';
1395
1396 return $self;
1397 }
1398 else {
1399 $self->in_storage(0);
1400 return $self;
1401 }
1402}
1403
1404
5160b401 1405=head2 throw_exception
701da8c4 1406
a2531bf2 1407See L<DBIx::Class::Schema/throw_exception>.
701da8c4 1408
1409=cut
1410
1411sub throw_exception {
1412 my $self=shift;
1a58752c 1413
66cab05c 1414 if (ref $self && ref $self->result_source && $self->result_source->schema) {
1a58752c 1415 $self->result_source->schema->throw_exception(@_)
1416 }
1417 else {
1418 DBIx::Class::Exception->throw(@_);
701da8c4 1419 }
1420}
1421
33cf6616 1422=head2 id
1423
a2531bf2 1424 my @pk = $row->id;
1425
1426=over
1427
1428=item Arguments: none
1429
1430=item Returns: A list of primary key values
1431
1432=back
1433
33cf6616 1434Returns the primary key(s) for a row. Can't be called as a class method.
f7043881 1435Actually implemented in L<DBIx::Class::PK>
33cf6616 1436
1437=head2 discard_changes
1438
a2531bf2 1439 $row->discard_changes
1440
1441=over
1442
1443=item Arguments: none
1444
1445=item Returns: nothing (updates object in-place)
1446
1447=back
1448
1449Retrieves and sets the row object data from the database, losing any
1450local changes made.
33cf6616 1451
1452This method can also be used to refresh from storage, retrieving any
1453changes made since the row was last read from storage. Actually
f7043881 1454implemented in L<DBIx::Class::PK>
33cf6616 1455
071bbccb 1456Note: If you are using L<DBIx::Class::Storage::DBI::Replicated> as your
1457storage, please kept in mind that if you L</discard_changes> on a row that you
1458just updated or created, you should wrap the entire bit inside a transaction.
1459Otherwise you run the risk that you insert or update to the master database
1460but read from a replicant database that has not yet been updated from the
1461master. This will result in unexpected results.
1462
33cf6616 1463=cut
1464
7624b19f 14651;
1466
7624b19f 1467=head1 AUTHORS
1468
daec44b8 1469Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 1470
1471=head1 LICENSE
1472
1473You may distribute this code under the same terms as Perl itself.
1474
1475=cut