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