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