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