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