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