Minor cleanup of ResultSource attributes
[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;
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
9c1700e3 23use namespace::clean;
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
50261284 66object until you pass or set the C<result_source> attribute, to a
a2531bf2 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
50261284 71some other attributes such as the C<result_source>.
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;
854929cb 137 $self->throw_exception (
138 "Unable to determine relationship '$relname' direction from '$us', "
139 . "possibly due to a missing reverse-relationship on '$relname' to '$us'."
140 );
370f2ba2 141 }
370f2ba2 142}
143
144sub __their_pk_needs_us { # this should maybe be in resultsource.
68888c09 145 my ($self, $relname) = @_;
370f2ba2 146 my $source = $self->result_source;
147 my $reverse = $source->reverse_relationship_info($relname);
148 my $rel_source = $source->related_source($relname);
149 my $us = { $self->get_columns };
150 foreach my $key (keys %$reverse) {
151 # if their primary key depends on us, then we have to
152 # just create a result and we'll fill it out afterwards
6d0ee587 153 return 1 if $rel_source->_pk_depends_on($key, $us);
370f2ba2 154 }
155 return 0;
156}
157
7624b19f 158sub new {
448f820f 159 my ($class, $attrs) = @_;
7624b19f 160 $class = ref $class if ref $class;
04786a4c 161
50261284 162 my $new = bless { _column_data => {} }, $class;
370f2ba2 163
7624b19f 164 if ($attrs) {
27f01d1f 165 $new->throw_exception("attrs must be a hashref")
166 unless ref($attrs) eq 'HASH';
b6d347e0 167
4376a157 168 my $source = delete $attrs->{-result_source};
169 if ( my $h = delete $attrs->{-source_handle} ) {
170 $source ||= $h->resolve;
171 }
172
173 $new->result_source($source) if $source;
174
175 if (my $col_from_rel = delete $attrs->{-cols_from_relations}) {
176 @{$new->{_ignore_at_insert}={}}{@$col_from_rel} = ();
177 }
178
61a622ee 179 my ($related,$inflated);
8222f722 180
61a622ee 181 foreach my $key (keys %$attrs) {
182 if (ref $attrs->{$key}) {
af2d42c0 183 ## Can we extract this lot to use with update(_or .. ) ?
1a58752c 184 $new->throw_exception("Can't do multi-create without result source")
185 unless $source;
370f2ba2 186 my $info = $source->relationship_info($key);
b82c8a28 187 my $acc_type = $info->{attrs}{accessor} || '';
188 if ($acc_type eq 'single') {
de7c7c53 189 my $rel_obj = delete $attrs->{$key};
6298a324 190 if(!blessed $rel_obj) {
370f2ba2 191 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 192 }
2bc3c81e 193
e0cdf2cb 194 if ($rel_obj->in_storage) {
d4fe33d0 195 $new->{_rel_in_storage}{$key} = 1;
e0cdf2cb 196 $new->set_from_related($key, $rel_obj);
197 } else {
09e1f723 198 MULTICREATE_DEBUG and warn "MC $new uninserted $key $rel_obj\n";
e0cdf2cb 199 }
2bc3c81e 200
de7c7c53 201 $related->{$key} = $rel_obj;
61a622ee 202 next;
b82c8a28 203 }
204 elsif ($acc_type eq 'multi' && ref $attrs->{$key} eq 'ARRAY' ) {
2ec8e594 205 my $others = delete $attrs->{$key};
e0cdf2cb 206 my $total = @$others;
207 my @objects;
208 foreach my $idx (0 .. $#$others) {
209 my $rel_obj = $others->[$idx];
6298a324 210 if(!blessed $rel_obj) {
370f2ba2 211 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 212 }
2bc3c81e 213
e0cdf2cb 214 if ($rel_obj->in_storage) {
d4fe33d0 215 $rel_obj->throw_exception ('A multi relationship can not be pre-existing when doing multicreate. Something went wrong');
e0cdf2cb 216 } else {
e0cdf2cb 217 MULTICREATE_DEBUG and
09e1f723 218 warn "MC $new uninserted $key $rel_obj (${\($idx+1)} of $total)\n";
e0cdf2cb 219 }
e0cdf2cb 220 push(@objects, $rel_obj);
2ec8e594 221 }
e0cdf2cb 222 $related->{$key} = \@objects;
2ec8e594 223 next;
b82c8a28 224 }
225 elsif ($acc_type eq 'filter') {
33dd4e80 226 ## 'filter' should disappear and get merged in with 'single' above!
2ec8e594 227 my $rel_obj = delete $attrs->{$key};
6298a324 228 if(!blessed $rel_obj) {
370f2ba2 229 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 230 }
d4fe33d0 231 if ($rel_obj->in_storage) {
232 $new->{_rel_in_storage}{$key} = 1;
233 }
234 else {
09e1f723 235 MULTICREATE_DEBUG and warn "MC $new uninserted $key $rel_obj";
e0cdf2cb 236 }
33dd4e80 237 $inflated->{$key} = $rel_obj;
61a622ee 238 next;
2ec8e594 239 } elsif ($class->has_column($key)
240 && $class->column_info($key)->{_inflate_info}) {
61a622ee 241 $inflated->{$key} = $attrs->{$key};
242 next;
243 }
244 }
245 $new->throw_exception("No such column $key on $class")
246 unless $class->has_column($key);
b6d347e0 247 $new->store_column($key => $attrs->{$key});
7624b19f 248 }
f90375dd 249
61a622ee 250 $new->{_relationship_data} = $related if $related;
251 $new->{_inflated_column} = $inflated if $inflated;
7624b19f 252 }
04786a4c 253
7624b19f 254 return $new;
255}
256
8091aa91 257=head2 insert
7624b19f 258
a2531bf2 259 $row->insert;
260
261=over
7624b19f 262
a2531bf2 263=item Arguments: none
264
265=item Returns: The Row object
266
267=back
268
269Inserts an object previously created by L</new> into the database if
5298bbb5 270it isn't already in there. Returns the object itself. To insert an
271entirely new row into the database, use L<DBIx::Class::ResultSet/create>.
7624b19f 272
e91e756c 273To fetch an uninserted row object, call
274L<new|DBIx::Class::ResultSet/new> on a resultset.
275
264f1571 276This will also insert any uninserted, related objects held inside this
277one, see L<DBIx::Class::ResultSet/create> for more details.
278
7624b19f 279=cut
280
281sub insert {
282 my ($self) = @_;
283 return $self if $self->in_storage;
6aba697f 284 my $source = $self->result_source;
aeb1bf75 285 $self->throw_exception("No result_source set on this object; can't insert")
286 unless $source;
6e399b4f 287
a85b7ebe 288 my $storage = $source->storage;
289
9c6d6d93 290 my $rollback_guard;
291
33dd4e80 292 # Check if we stored uninserted relobjs here in new()
b6d347e0 293 my %related_stuff = (%{$self->{_relationship_data} || {}},
33dd4e80 294 %{$self->{_inflated_column} || {}});
9c6d6d93 295
d4fe33d0 296 # insert what needs to be inserted before us
297 my %pre_insert;
298 for my $relname (keys %related_stuff) {
299 my $rel_obj = $related_stuff{$relname};
9c6d6d93 300
d4fe33d0 301 if (! $self->{_rel_in_storage}{$relname}) {
6298a324 302 next unless (blessed $rel_obj && $rel_obj->isa('DBIx::Class::Row'));
a8c98174 303
d4fe33d0 304 next unless $source->_pk_depends_on(
305 $relname, { $rel_obj->get_columns }
306 );
a8c98174 307
d4fe33d0 308 # The guard will save us if we blow out of this scope via die
a85b7ebe 309 $rollback_guard ||= $storage->txn_scope_guard;
9c6d6d93 310
de404241 311 MULTICREATE_DEBUG and warn "MC $self pre-reconstructing $relname $rel_obj\n";
e0cdf2cb 312
380d34f5 313 my $them = { %{$rel_obj->{_relationship_data} || {} }, $rel_obj->get_columns };
68888c09 314 my $existing;
315
316 # if there are no keys - nothing to search for
317 if (keys %$them and $existing = $self->result_source
318 ->related_source($relname)
319 ->resultset
320 ->find($them)
321 ) {
322 %{$rel_obj} = %{$existing};
323 }
324 else {
325 $rel_obj->insert;
326 }
d4fe33d0 327
d4fe33d0 328 $self->{_rel_in_storage}{$relname} = 1;
33dd4e80 329 }
d4fe33d0 330
331 $self->set_from_related($relname, $rel_obj);
332 delete $related_stuff{$relname};
333 }
334
335 # start a transaction here if not started yet and there is more stuff
336 # to insert after us
337 if (keys %related_stuff) {
a85b7ebe 338 $rollback_guard ||= $storage->txn_scope_guard
1e45aa87 339 }
340
09e1f723 341 MULTICREATE_DEBUG and do {
342 no warnings 'uninitialized';
343 warn "MC $self inserting (".join(', ', $self->get_columns).")\n";
344 };
a85b7ebe 345
8b9473f5 346 # perform the insert - the storage will return everything it is asked to
347 # (autoinc primary columns and any retrieve_on_insert columns)
a85b7ebe 348 my %current_rowdata = $self->get_columns;
a85b7ebe 349 my $returned_cols = $storage->insert(
1e45aa87 350 $source,
8b9473f5 351 { %current_rowdata }, # what to insert, copy because the storage *will* change it
1e45aa87 352 );
353
a85b7ebe 354 for (keys %$returned_cols) {
8b9473f5 355 $self->store_column($_, $returned_cols->{$_})
356 # this ensures we fire store_column only once
357 # (some asshats like overriding it)
358 if (
359 (! defined $current_rowdata{$_})
360 or
361 ( $current_rowdata{$_} ne $returned_cols->{$_})
362 );
ac8e89d7 363 }
33dd4e80 364
370f2ba2 365 $self->{_dirty_columns} = {};
366 $self->{related_resultsets} = {};
367
d4fe33d0 368 foreach my $relname (keys %related_stuff) {
31c3800e 369 next unless $source->has_relationship ($relname);
370
371 my @cands = ref $related_stuff{$relname} eq 'ARRAY'
372 ? @{$related_stuff{$relname}}
373 : $related_stuff{$relname}
374 ;
d4fe33d0 375
6298a324 376 if (@cands && blessed $cands[0] && $cands[0]->isa('DBIx::Class::Row')
31c3800e 377 ) {
d4fe33d0 378 my $reverse = $source->reverse_relationship_info($relname);
379 foreach my $obj (@cands) {
380 $obj->set_from_related($_, $self) for keys %$reverse;
68888c09 381 if ($self->__their_pk_needs_us($relname)) {
d4fe33d0 382 if (exists $self->{_ignore_at_insert}{$relname}) {
383 MULTICREATE_DEBUG and warn "MC $self skipping post-insert on $relname";
65ee2b31 384 }
385 else {
386 MULTICREATE_DEBUG and warn "MC $self inserting $relname $obj";
387 $obj->insert;
370f2ba2 388 }
d4fe33d0 389 } else {
390 MULTICREATE_DEBUG and warn "MC $self post-inserting $obj";
391 $obj->insert();
8222f722 392 }
33dd4e80 393 }
394 }
395 }
33dd4e80 396
7624b19f 397 $self->in_storage(1);
d4fe33d0 398 delete $self->{_orig_ident};
613a5b03 399 delete $self->{_orig_ident_failreason};
d4fe33d0 400 delete $self->{_ignore_at_insert};
401 $rollback_guard->commit if $rollback_guard;
402
7624b19f 403 return $self;
404}
405
8091aa91 406=head2 in_storage
7624b19f 407
a2531bf2 408 $row->in_storage; # Get value
409 $row->in_storage(1); # Set value
410
411=over
412
413=item Arguments: none or 1|0
414
415=item Returns: 1|0
416
417=back
7624b19f 418
e91e756c 419Indicates whether the object exists as a row in the database or
420not. This is set to true when L<DBIx::Class::ResultSet/find>,
421L<DBIx::Class::ResultSet/create> or L<DBIx::Class::ResultSet/insert>
b6d347e0 422are used.
e91e756c 423
424Creating a row object using L<DBIx::Class::ResultSet/new>, or calling
425L</delete> on one, sets it to false.
7624b19f 426
427=cut
428
429sub in_storage {
430 my ($self, $val) = @_;
431 $self->{_in_storage} = $val if @_ > 1;
63bb9738 432 return $self->{_in_storage} ? 1 : 0;
7624b19f 433}
434
8091aa91 435=head2 update
7624b19f 436
a2531bf2 437 $row->update(\%columns?)
438
439=over
7624b19f 440
a2531bf2 441=item Arguments: none or a hashref
7624b19f 442
a2531bf2 443=item Returns: The Row object
444
445=back
446
447Throws an exception if the row object is not yet in the database,
448according to L</in_storage>.
449
450This method issues an SQL UPDATE query to commit any changes to the
d6988be8 451object to the database if required (see L</get_dirty_columns>).
452It throws an exception if a proper WHERE clause uniquely identifying
453the database row can not be constructed (see
454L<significance of primary keys|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
455for more details).
a2531bf2 456
0d0fcdbf 457Also takes an optional hashref of C<< column_name => value >> pairs
a2531bf2 458to update on the object first. Be aware that the hashref will be
459passed to C<set_inflated_columns>, which might edit it in place, so
460don't rely on it being the same after a call to C<update>. If you
461need to preserve the hashref, it is sufficient to pass a shallow copy
462to C<update>, e.g. ( { %{ $href } } )
d5d833d9 463
05d1bc9c 464If the values passed or any of the column values set on the object
48580715 465contain scalar references, e.g.:
05d1bc9c 466
a2531bf2 467 $row->last_modified(\'NOW()');
05d1bc9c 468 # OR
a2531bf2 469 $row->update({ last_modified => \'NOW()' });
05d1bc9c 470
471The update will pass the values verbatim into SQL. (See
472L<SQL::Abstract> docs). The values in your Row object will NOT change
473as a result of the update call, if you want the object to be updated
474with the actual values from the database, call L</discard_changes>
475after the update.
476
a2531bf2 477 $row->update()->discard_changes();
478
479To determine before calling this method, which column values have
480changed and will be updated, call L</get_dirty_columns>.
481
482To check if any columns will be updated, call L</is_changed>.
483
484To force a column to be updated, call L</make_column_dirty> before
485this method.
05d1bc9c 486
7624b19f 487=cut
488
489sub update {
490 my ($self, $upd) = @_;
cf856357 491
bacf6f12 492 $self->set_inflated_columns($upd) if $upd;
de5ce481 493
014789be 494 my %to_update = $self->get_dirty_columns
495 or return $self;
496
497 my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
de5ce481 498 $self->throw_exception( "Not in database" ) unless $self->in_storage;
499
613a5b03 500 $self->throw_exception($self->{_orig_ident_failreason})
ad3f2296 501 if ! keys %$ident_cond;
502
88cb6a1d 503 my $rows = $self->result_source->storage->update(
cf856357 504 $self->result_source, \%to_update, $ident_cond
505 );
7624b19f 506 if ($rows == 0) {
701da8c4 507 $self->throw_exception( "Can't update ${self}: row not found" );
7624b19f 508 } elsif ($rows > 1) {
701da8c4 509 $self->throw_exception("Can't update ${self}: updated more than one row");
7624b19f 510 }
511 $self->{_dirty_columns} = {};
64acc2bc 512 $self->{related_resultsets} = {};
cf856357 513 delete $self->{_orig_ident};
7624b19f 514 return $self;
515}
516
8091aa91 517=head2 delete
7624b19f 518
a2531bf2 519 $row->delete
520
521=over
522
523=item Arguments: none
7624b19f 524
a2531bf2 525=item Returns: The Row object
526
527=back
528
529Throws an exception if the object is not in the database according to
d6988be8 530L</in_storage>. Also throws an exception if a proper WHERE clause
531uniquely identifying the database row can not be constructed (see
532L<significance of primary keys|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
533for more details).
a2531bf2 534
535The object is still perfectly usable, but L</in_storage> will
ea36f4e4 536now return 0 and the object must be reinserted using L</insert>
b6d347e0 537before it can be used to L</update> the row again.
a2531bf2 538
539If you delete an object in a class with a C<has_many> relationship, an
540attempt is made to delete all the related objects as well. To turn
541this behaviour off, pass C<< cascade_delete => 0 >> in the C<$attr>
542hashref of the relationship, see L<DBIx::Class::Relationship>. Any
543database-level cascade or restrict will take precedence over a
281e677e 544DBIx-Class-based cascading delete, since DBIx-Class B<deletes the
545main row first> and only then attempts to delete any remaining related
546rows.
a2531bf2 547
b1d16ffd 548If you delete an object within a txn_do() (see L<DBIx::Class::Storage/txn_do>)
549and the transaction subsequently fails, the row object will remain marked as
550not being in storage. If you know for a fact that the object is still in
551storage (i.e. by inspecting the cause of the transaction's failure), you can
552use C<< $obj->in_storage(1) >> to restore consistency between the object and
553the database. This would allow a subsequent C<< $obj->delete >> to work
554as expected.
555
a2531bf2 556See also L<DBIx::Class::ResultSet/delete>.
7624b19f 557
558=cut
559
560sub delete {
561 my $self = shift;
562 if (ref $self) {
701da8c4 563 $self->throw_exception( "Not in database" ) unless $self->in_storage;
cf856357 564
728e60a3 565 my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
613a5b03 566 $self->throw_exception($self->{_orig_ident_failreason})
4b12b3c2 567 if ! keys %$ident_cond;
cf856357 568
88cb6a1d 569 $self->result_source->storage->delete(
cf856357 570 $self->result_source, $ident_cond
571 );
572
613a5b03 573 delete $self->{_orig_ident}; # no longer identifiable
7624b19f 574 $self->in_storage(undef);
cf856357 575 }
576 else {
5298bbb5 577 my $rsrc = try { $self->result_source_instance }
578 or $self->throw_exception("Can't do class delete without a ResultSource instance");
579
aeb1bf75 580 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
581 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
5298bbb5 582 $rsrc->resultset->search(@_)->delete;
7624b19f 583 }
584 return $self;
585}
586
8091aa91 587=head2 get_column
7624b19f 588
a2531bf2 589 my $val = $row->get_column($col);
590
591=over
592
593=item Arguments: $columnname
594
595=item Returns: The value of the column
596
597=back
598
599Throws an exception if the column name given doesn't exist according
600to L</has_column>.
7624b19f 601
e91e756c 602Returns a raw column value from the row object, if it has already
603been fetched from the database or set by an accessor.
604
605If an L<inflated value|DBIx::Class::InflateColumn> has been set, it
606will be deflated and returned.
7624b19f 607
ea36f4e4 608Note that if you used the C<columns> or the C<select/as>
609L<search attributes|DBIx::Class::ResultSet/ATTRIBUTES> on the resultset from
610which C<$row> was derived, and B<did not include> C<$columnname> in the list,
611this method will return C<undef> even if the database contains some value.
612
a2531bf2 613To retrieve all loaded column values as a hash, use L</get_columns>.
614
7624b19f 615=cut
616
617sub get_column {
618 my ($self, $column) = @_;
701da8c4 619 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
aeb1bf75 620 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
61a622ee 621 if (exists $self->{_inflated_column}{$column}) {
622 return $self->store_column($column,
b6d347e0 623 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
61a622ee 624 }
701da8c4 625 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
7624b19f 626 return undef;
627}
628
9b83fccd 629=head2 has_column_loaded
630
a2531bf2 631 if ( $row->has_column_loaded($col) ) {
9b83fccd 632 print "$col has been loaded from db";
633 }
634
a2531bf2 635=over
636
637=item Arguments: $columnname
638
639=item Returns: 0|1
640
641=back
642
9b83fccd 643Returns a true value if the column value has been loaded from the
644database (or set locally).
645
646=cut
647
def81720 648sub has_column_loaded {
649 my ($self, $column) = @_;
650 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
61a622ee 651 return 1 if exists $self->{_inflated_column}{$column};
aeb1bf75 652 return exists $self->{_column_data}{$column};
def81720 653}
654
8091aa91 655=head2 get_columns
076a6864 656
a2531bf2 657 my %data = $row->get_columns;
658
659=over
660
661=item Arguments: none
076a6864 662
a2531bf2 663=item Returns: A hash of columnname, value pairs.
664
665=back
666
667Returns all loaded column data as a hash, containing raw values. To
668get just one value for a particular column, use L</get_column>.
076a6864 669
c0a171bf 670See L</get_inflated_columns> to get the inflated values.
671
076a6864 672=cut
673
674sub get_columns {
675 my $self = shift;
61a622ee 676 if (exists $self->{_inflated_column}) {
677 foreach my $col (keys %{$self->{_inflated_column}}) {
678 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
c4a30d56 679 unless exists $self->{_column_data}{$col};
61a622ee 680 }
681 }
cb5f2eea 682 return %{$self->{_column_data}};
d7156e50 683}
684
685=head2 get_dirty_columns
686
a2531bf2 687 my %data = $row->get_dirty_columns;
688
689=over
690
691=item Arguments: none
d7156e50 692
a2531bf2 693=item Returns: A hash of column, value pairs
694
695=back
696
697Only returns the column, value pairs for those columns that have been
698changed on this object since the last L</update> or L</insert> call.
699
700See L</get_columns> to fetch all column/value pairs.
d7156e50 701
702=cut
703
704sub get_dirty_columns {
705 my $self = shift;
706 return map { $_ => $self->{_column_data}{$_} }
707 keys %{$self->{_dirty_columns}};
076a6864 708}
709
6dbea98e 710=head2 make_column_dirty
711
a2531bf2 712 $row->make_column_dirty($col)
713
714=over
715
716=item Arguments: $columnname
717
718=item Returns: undefined
719
720=back
721
722Throws an exception if the column does not exist.
723
724Marks a column as having been changed regardless of whether it has
b6d347e0 725really changed.
6dbea98e 726
727=cut
728sub make_column_dirty {
729 my ($self, $column) = @_;
730
731 $self->throw_exception( "No such column '${column}'" )
732 unless exists $self->{_column_data}{$column} || $self->has_column($column);
497d874a 733
b6d347e0 734 # the entire clean/dirty code relies on exists, not on true/false
497d874a 735 return 1 if exists $self->{_dirty_columns}{$column};
736
6dbea98e 737 $self->{_dirty_columns}{$column} = 1;
497d874a 738
739 # if we are just now making the column dirty, and if there is an inflated
740 # value, force it over the deflated one
741 if (exists $self->{_inflated_column}{$column}) {
742 $self->store_column($column,
743 $self->_deflated_column(
744 $column, $self->{_inflated_column}{$column}
745 )
746 );
747 }
6dbea98e 748}
749
ba4a6453 750=head2 get_inflated_columns
751
e91e756c 752 my %inflated_data = $obj->get_inflated_columns;
ba4a6453 753
a2531bf2 754=over
755
756=item Arguments: none
757
758=item Returns: A hash of column, object|value pairs
759
760=back
761
762Returns a hash of all column keys and associated values. Values for any
763columns set to use inflation will be inflated and returns as objects.
764
765See L</get_columns> to get the uninflated values.
766
767See L<DBIx::Class::InflateColumn> for how to setup inflation.
ba4a6453 768
769=cut
770
771sub get_inflated_columns {
772 my $self = shift;
d61b2132 773
52416317 774 my $loaded_colinfo = $self->columns_info ([
775 grep { $self->has_column_loaded($_) } $self->columns
776 ]);
d61b2132 777
778 my %inflated;
52416317 779 for my $col (keys %$loaded_colinfo) {
780 if (exists $loaded_colinfo->{$col}{accessor}) {
781 my $acc = $loaded_colinfo->{$col}{accessor};
9c042209 782 $inflated{$col} = $self->$acc if defined $acc;
d61b2132 783 }
784 else {
785 $inflated{$col} = $self->$col;
786 }
787 }
788
789 # return all loaded columns with the inflations overlayed on top
edc89064 790 return %{ { $self->get_columns, %inflated } };
ba4a6453 791}
792
ca8a1270 793sub _is_column_numeric {
0bb1a52f 794 my ($self, $column) = @_;
795 my $colinfo = $self->column_info ($column);
796
797 # cache for speed (the object may *not* have a resultsource instance)
50261284 798 if (
799 ! defined $colinfo->{is_numeric}
800 and
801 my $storage = try { $self->result_source->schema->storage }
802 ) {
0bb1a52f 803 $colinfo->{is_numeric} =
50261284 804 $storage->is_datatype_numeric ($colinfo->{data_type})
0bb1a52f 805 ? 1
806 : 0
807 ;
808 }
809
810 return $colinfo->{is_numeric};
811}
812
8091aa91 813=head2 set_column
7624b19f 814
a2531bf2 815 $row->set_column($col => $val);
816
817=over
818
819=item Arguments: $columnname, $value
820
821=item Returns: $value
822
823=back
7624b19f 824
e91e756c 825Sets a raw column value. If the new value is different from the old one,
a2531bf2 826the column is marked as dirty for when you next call L</update>.
7624b19f 827
ea36f4e4 828If passed an object or reference as a value, this method will happily
829attempt to store it, and a later L</insert> or L</update> will try and
a2531bf2 830stringify/numify as appropriate. To set an object to be deflated
831instead, see L</set_inflated_columns>.
e91e756c 832
7624b19f 833=cut
834
835sub set_column {
1d0057bd 836 my ($self, $column, $new_value) = @_;
837
cf856357 838 # if we can't get an ident condition on first try - mark the object as unidentifiable
613a5b03 839 # (by using an empty hashref) and store the error for further diag
840 unless ($self->{_orig_ident}) {
841 try {
842 $self->{_orig_ident} = $self->ident_condition
843 }
844 catch {
845 $self->{_orig_ident_failreason} = $_;
846 $self->{_orig_ident} = {};
847 };
848 }
1d0057bd 849
cf856357 850 my $old_value = $self->get_column($column);
b236052f 851 $new_value = $self->store_column($column, $new_value);
8f9eff75 852
cde96798 853 my $dirty =
854 $self->{_dirty_columns}{$column}
855 ||
856 $self->in_storage # no point tracking dirtyness on uninserted data
857 ? ! $self->_eq_column_values ($column, $old_value, $new_value)
858 : 1
859 ;
8f9eff75 860
35f5c265 861 if ($dirty) {
862 # FIXME sadly the update code just checks for keys, not for their value
863 $self->{_dirty_columns}{$column} = 1;
864
865 # Clear out the relation/inflation cache related to this column
866 #
867 # FIXME - this is a quick *largely incorrect* hack, pending a more
868 # serious rework during the merge of single and filter rels
869 my $rels = $self->result_source->{_relationships};
870 for my $rel (keys %$rels) {
871
872 my $acc = $rels->{$rel}{attrs}{accessor} || '';
873
874 if ( $acc eq 'single' and $rels->{$rel}{attrs}{fk_columns}{$column} ) {
875 delete $self->{related_resultsets}{$rel};
876 delete $self->{_relationship_data}{$rel};
877 #delete $self->{_inflated_column}{$rel};
878 }
879 elsif ( $acc eq 'filter' and $rel eq $column) {
880 delete $self->{related_resultsets}{$rel};
881 #delete $self->{_relationship_data}{$rel};
882 delete $self->{_inflated_column}{$rel};
883 }
884 }
885 }
e60dc79f 886
1d0057bd 887 return $new_value;
7624b19f 888}
889
cde96798 890sub _eq_column_values {
891 my ($self, $col, $old, $new) = @_;
892
893 if (defined $old xor defined $new) {
894 return 0;
895 }
896 elsif (not defined $old) { # both undef
897 return 1;
898 }
899 elsif ($old eq $new) {
900 return 1;
901 }
902 elsif ($self->_is_column_numeric($col)) { # do a numeric comparison if datatype allows it
903 return $old == $new;
904 }
905 else {
906 return 0;
907 }
908}
909
8091aa91 910=head2 set_columns
076a6864 911
a2531bf2 912 $row->set_columns({ $col => $val, ... });
913
b6d347e0 914=over
076a6864 915
a2531bf2 916=item Arguments: \%columndata
917
918=item Returns: The Row object
919
920=back
921
922Sets multiple column, raw value pairs at once.
923
924Works as L</set_column>.
076a6864 925
926=cut
927
928sub set_columns {
929 my ($self,$data) = @_;
a2ca474b 930 foreach my $col (keys %$data) {
931 $self->set_column($col,$data->{$col});
076a6864 932 }
c01ab172 933 return $self;
076a6864 934}
935
bacf6f12 936=head2 set_inflated_columns
937
a2531bf2 938 $row->set_inflated_columns({ $col => $val, $relname => $obj, ... });
939
940=over
941
942=item Arguments: \%columndata
943
944=item Returns: The Row object
945
946=back
947
948Sets more than one column value at once. Any inflated values are
b6d347e0 949deflated and the raw values stored.
bacf6f12 950
a2531bf2 951Any related values passed as Row objects, using the relation name as a
952key, are reduced to the appropriate foreign key values and stored. If
953instead of related row objects, a hashref of column, value data is
954passed, will create the related object first then store.
955
956Will even accept arrayrefs of data as a value to a
957L<DBIx::Class::Relationship/has_many> key, and create the related
958objects if necessary.
959
c1300297 960Be aware that the input hashref might be edited in place, so don't rely
a2531bf2 961on it being the same after a call to C<set_inflated_columns>. If you
962need to preserve the hashref, it is sufficient to pass a shallow copy
963to C<set_inflated_columns>, e.g. ( { %{ $href } } )
964
965See also L<DBIx::Class::Relationship::Base/set_from_related>.
bacf6f12 966
967=cut
968
969sub set_inflated_columns {
970 my ( $self, $upd ) = @_;
971 foreach my $key (keys %$upd) {
972 if (ref $upd->{$key}) {
973 my $info = $self->relationship_info($key);
b82c8a28 974 my $acc_type = $info->{attrs}{accessor} || '';
975 if ($acc_type eq 'single') {
bacf6f12 976 my $rel = delete $upd->{$key};
977 $self->set_from_related($key => $rel);
a7be8807 978 $self->{_relationship_data}{$key} = $rel;
bacf6f12 979 }
b82c8a28 980 elsif ($acc_type eq 'multi') {
981 $self->throw_exception(
982 "Recursive update is not supported over relationships of type '$acc_type' ($key)"
983 );
984 }
985 elsif ($self->has_column($key) && exists $self->column_info($key)->{_inflate_info}) {
a7be8807 986 $self->set_inflated_column($key, delete $upd->{$key});
bacf6f12 987 }
988 }
989 }
b6d347e0 990 $self->set_columns($upd);
bacf6f12 991}
992
8091aa91 993=head2 copy
076a6864 994
995 my $copy = $orig->copy({ change => $to, ... });
996
a2531bf2 997=over
998
999=item Arguments: \%replacementdata
1000
1001=item Returns: The Row object copy
1002
1003=back
1004
1005Inserts a new row into the database, as a copy of the original
1006object. If a hashref of replacement data is supplied, these will take
ce0893e0 1007precedence over data in the original. Also any columns which have
1008the L<column info attribute|DBIx::Class::ResultSource/add_columns>
1009C<< is_auto_increment => 1 >> are explicitly removed before the copy,
1010so that the database can insert its own autoincremented values into
1011the new object.
a2531bf2 1012
f928c965 1013Relationships will be followed by the copy procedure B<only> if the
48580715 1014relationship specifies a true value for its
f928c965 1015L<cascade_copy|DBIx::Class::Relationship::Base> attribute. C<cascade_copy>
1016is set by default on C<has_many> relationships and unset on all others.
076a6864 1017
1018=cut
1019
c01ab172 1020sub copy {
1021 my ($self, $changes) = @_;
333cce60 1022 $changes ||= {};
fde6e28e 1023 my $col_data = { %{$self->{_column_data}} };
52416317 1024
1025 my $colinfo = $self->columns_info([ keys %$col_data ]);
fde6e28e 1026 foreach my $col (keys %$col_data) {
1027 delete $col_data->{$col}
52416317 1028 if $colinfo->{$col}{is_auto_increment};
fde6e28e 1029 }
04786a4c 1030
1031 my $new = { _column_data => $col_data };
1032 bless $new, ref $self;
1033
83419ec6 1034 $new->result_source($self->result_source);
bacf6f12 1035 $new->set_inflated_columns($changes);
333cce60 1036 $new->insert;
35688220 1037
b6d347e0 1038 # Its possible we'll have 2 relations to the same Source. We need to make
48580715 1039 # sure we don't try to insert the same row twice else we'll violate unique
35688220 1040 # constraints
1041 my $rels_copied = {};
1042
333cce60 1043 foreach my $rel ($self->result_source->relationships) {
1044 my $rel_info = $self->result_source->relationship_info($rel);
35688220 1045
1046 next unless $rel_info->{attrs}{cascade_copy};
b6d347e0 1047
6d0ee587 1048 my $resolved = $self->result_source->_resolve_condition(
16053767 1049 $rel_info->{cond}, $rel, $new, $rel
35688220 1050 );
1051
1052 my $copied = $rels_copied->{ $rel_info->{source} } ||= {};
1053 foreach my $related ($self->search_related($rel)) {
1054 my $id_str = join("\0", $related->id);
1055 next if $copied->{$id_str};
1056 $copied->{$id_str} = 1;
1057 my $rel_copy = $related->copy($resolved);
333cce60 1058 }
b6d347e0 1059
333cce60 1060 }
2c4c67b6 1061 return $new;
c01ab172 1062}
1063
8091aa91 1064=head2 store_column
7624b19f 1065
a2531bf2 1066 $row->store_column($col => $val);
7624b19f 1067
a2531bf2 1068=over
1069
1070=item Arguments: $columnname, $value
1071
ea36f4e4 1072=item Returns: The value sent to storage
a2531bf2 1073
1074=back
1075
1076Set a raw value for a column without marking it as changed. This
1077method is used internally by L</set_column> which you should probably
1078be using.
1079
1080This is the lowest level at which data is set on a row object,
1081extend this method to catch all data setting methods.
7624b19f 1082
1083=cut
1084
1085sub store_column {
1086 my ($self, $column, $value) = @_;
75d07914 1087 $self->throw_exception( "No such column '${column}'" )
d7156e50 1088 unless exists $self->{_column_data}{$column} || $self->has_column($column);
75d07914 1089 $self->throw_exception( "set_column called for ${column} without value" )
7624b19f 1090 if @_ < 3;
1091 return $self->{_column_data}{$column} = $value;
1092}
1093
b52e9bf8 1094=head2 inflate_result
1095
c01ab172 1096 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 1097
a2531bf2 1098=over
1099
d4a20f38 1100=item Arguments: $result_source, \%columndata, \%prefetcheddata
a2531bf2 1101
1102=item Returns: A Row object
1103
1104=back
1105
1106All L<DBIx::Class::ResultSet> methods that retrieve data from the
1107database and turn it into row objects call this method.
1108
1109Extend this method in your Result classes to hook into this process,
1110for example to rebless the result into a different class.
1111
1112Reblessing can also be done more easily by setting C<result_class> in
1113your Result class. See L<DBIx::Class::ResultSource/result_class>.
b52e9bf8 1114
db2b2eb6 1115Different types of results can also be created from a particular
1116L<DBIx::Class::ResultSet>, see L<DBIx::Class::ResultSet/result_class>.
1117
b52e9bf8 1118=cut
1119
1120sub inflate_result {
d4a20f38 1121 my ($class, $source, $me, $prefetch) = @_;
1122
50261284 1123 $source = $source->resolve
1124 if $source->isa('DBIx::Class::ResultSourceHandle');
aec3eff1 1125
50261284 1126 my $new = bless
1127 { _column_data => $me, _result_source => $source },
1128 ref $class || $class
1129 ;
04786a4c 1130
64acc2bc 1131 foreach my $pre (keys %{$prefetch||{}}) {
35c77aa3 1132
13d06949 1133 my $pre_source = $source->related_source($pre)
1134 or $class->throw_exception("Can't prefetch non-existent relationship ${pre}");
35c77aa3 1135
13d06949 1136 my $accessor = $source->relationship_info($pre)->{attrs}{accessor}
1137 or $class->throw_exception("No accessor for prefetched $pre");
35c77aa3 1138
13d06949 1139 my @pre_vals;
1140 if (ref $prefetch->{$pre}[0] eq 'ARRAY') {
1141 @pre_vals = @{$prefetch->{$pre}};
1142 }
1143 elsif ($accessor eq 'multi') {
1144 $class->throw_exception("Implicit prefetch (via select/columns) not supported with accessor 'multi'");
1145 }
1146 else {
1147 @pre_vals = $prefetch->{$pre};
1148 }
1149
1150 my @pre_objects;
1151 for my $me_pref (@pre_vals) {
1152
1153 # FIXME - this should not be necessary
35c77aa3 1154 # the collapser currently *could* return bogus elements with all
1155 # columns set to undef
1156 my $has_def;
1157 for (values %{$me_pref->[0]}) {
1158 if (defined $_) {
1159 $has_def++;
1160 last;
1161 }
a86b1efe 1162 }
35c77aa3 1163 next unless $has_def;
1164
1165 push @pre_objects, $pre_source->result_class->inflate_result(
1166 $pre_source, @$me_pref
1167 );
13d06949 1168 }
35c77aa3 1169
13d06949 1170 if ($accessor eq 'single') {
1171 $new->{_relationship_data}{$pre} = $pre_objects[0];
b52e9bf8 1172 }
13d06949 1173 elsif ($accessor eq 'filter') {
1174 $new->{_inflated_column}{$pre} = $pre_objects[0];
1175 }
1176
1177 $new->related_resultset($pre)->set_cache(\@pre_objects);
b52e9bf8 1178 }
35c77aa3 1179
1180 $new->in_storage (1);
7624b19f 1181 return $new;
1182}
1183
9b465d00 1184=head2 update_or_insert
7624b19f 1185
a2531bf2 1186 $row->update_or_insert
1187
1188=over
7624b19f 1189
a2531bf2 1190=item Arguments: none
1191
1192=item Returns: Result of update or insert operation
1193
1194=back
1195
1196L</Update>s the object if it's already in the database, according to
1197L</in_storage>, else L</insert>s it.
7624b19f 1198
9b83fccd 1199=head2 insert_or_update
1200
1201 $obj->insert_or_update
1202
1203Alias for L</update_or_insert>
1204
7624b19f 1205=cut
1206
370f2ba2 1207sub insert_or_update { shift->update_or_insert(@_) }
1208
9b465d00 1209sub update_or_insert {
7624b19f 1210 my $self = shift;
1211 return ($self->in_storage ? $self->update : $self->insert);
1212}
1213
8091aa91 1214=head2 is_changed
7624b19f 1215
a2531bf2 1216 my @changed_col_names = $row->is_changed();
1217 if ($row->is_changed()) { ... }
1218
1219=over
7624b19f 1220
a2531bf2 1221=item Arguments: none
1222
1223=item Returns: 0|1 or @columnnames
1224
1225=back
1226
1227In list context returns a list of columns with uncommited changes, or
9b83fccd 1228in scalar context returns a true value if there are uncommitted
1229changes.
1230
7624b19f 1231=cut
1232
1233sub is_changed {
1234 return keys %{shift->{_dirty_columns} || {}};
1235}
228dbcb4 1236
1237=head2 is_column_changed
1238
a2531bf2 1239 if ($row->is_column_changed('col')) { ... }
1240
1241=over
1242
1243=item Arguments: $columname
1244
1245=item Returns: 0|1
1246
1247=back
228dbcb4 1248
9b83fccd 1249Returns a true value if the column has uncommitted changes.
1250
228dbcb4 1251=cut
1252
1253sub is_column_changed {
1254 my( $self, $col ) = @_;
1255 return exists $self->{_dirty_columns}->{$col};
1256}
7624b19f 1257
097d3227 1258=head2 result_source
1259
a2531bf2 1260 my $resultsource = $row->result_source;
1261
1262=over
1263
50261284 1264=item Arguments: $result_source_instance
097d3227 1265
a2531bf2 1266=item Returns: a ResultSource instance
1267
1268=back
1269
1270Accessor to the L<DBIx::Class::ResultSource> this object was created from.
87c4e602 1271
5298bbb5 1272=cut
1273
1274sub result_source {
1275 $_[0]->throw_exception( 'result_source can be called on instances only' )
1276 unless ref $_[0];
1277
1278 @_ > 1
1279 ? $_[0]->{_result_source} = $_[1]
1280
1281 # note this is a || not a ||=, the difference is important
1282 : $_[0]->{_result_source} || do {
1283 my $class = ref $_[0];
1284 $_[0]->can('result_source_instance')
1285 ? $_[0]->result_source_instance
1286 : $_[0]->throw_exception(
1287 "No result source instance registered for $class, did you forget to call $class->table(...) ?"
1288 )
1289 }
1290 ;
1291}
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
4376a157 1441 if (ref $self && ref $self->result_source ) {
1442 $self->result_source->throw_exception(@_)
1a58752c 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 1464=head1 AUTHORS
1465
daec44b8 1466Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 1467
1468=head1 LICENSE
1469
1470You may distribute this code under the same terms as Perl itself.
1471
1472=cut
fde05eb9 1473
14741;