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