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