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