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