added entry in Changes for versioning branch
[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/;
701da8c4 7use Carp::Clan qw/^DBIx::Class/;
33dd4e80 8use Scalar::Util ();
9c6d6d93 9use Scope::Guard;
1edd1722 10
aec3eff1 11__PACKAGE__->mk_group_accessors('simple' => qw/_source_handle/);
8c49f629 12
75d07914 13=head1 NAME
7624b19f 14
15DBIx::Class::Row - Basic row methods
16
17=head1 SYNOPSIS
18
19=head1 DESCRIPTION
20
21This class is responsible for defining and doing basic operations on rows
1ea77c14 22derived from L<DBIx::Class::ResultSource> objects.
7624b19f 23
24=head1 METHODS
25
8091aa91 26=head2 new
7624b19f 27
28 my $obj = My::Class->new($attrs);
29
30Creates a new row object from column => value mappings passed as a hash ref
31
33dd4e80 32Passing an object, or an arrayref of objects as a value will call
33L<DBIx::Class::Relationship::Base/set_from_related> for you. When
34passed a hashref or an arrayref of hashrefs as the value, these will
35be turned into objects via new_related, and treated as if you had
36passed objects.
37
264f1571 38For a more involved explanation, see L<DBIx::Class::ResultSet/create>.
39
7624b19f 40=cut
41
33dd4e80 42## 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().
43## This only works because DBIC doesnt yet care to check whether the new_related objects have been passed all their mandatory columns
44## When doing the later insert, we need to make sure the PKs are set.
45## using _relationship_data in new and funky ways..
46## check Relationship::CascadeActions and Relationship::Accessor for compat
47## tests!
48
7624b19f 49sub new {
448f820f 50 my ($class, $attrs) = @_;
7624b19f 51 $class = ref $class if ref $class;
04786a4c 52
53 my $new = { _column_data => {} };
54 bless $new, $class;
55
448f820f 56 if (my $handle = delete $attrs->{-source_handle}) {
57 $new->_source_handle($handle);
58 }
e9fe476b 59 if (my $source = delete $attrs->{-result_source}) {
60 $new->result_source($source);
61 }
a6a280b9 62
7624b19f 63 if ($attrs) {
27f01d1f 64 $new->throw_exception("attrs must be a hashref")
65 unless ref($attrs) eq 'HASH';
61a622ee 66
67 my ($related,$inflated);
de7c7c53 68 ## Pretend all the rels are actual objects, unset below if not, for insert() to fix
69 $new->{_rel_in_storage} = 1;
8222f722 70
61a622ee 71 foreach my $key (keys %$attrs) {
72 if (ref $attrs->{$key}) {
af2d42c0 73 ## Can we extract this lot to use with update(_or .. ) ?
61a622ee 74 my $info = $class->relationship_info($key);
75 if ($info && $info->{attrs}{accessor}
c4a30d56 76 && $info->{attrs}{accessor} eq 'single')
61a622ee 77 {
de7c7c53 78 my $rel_obj = delete $attrs->{$key};
33dd4e80 79 if(!Scalar::Util::blessed($rel_obj)) {
2ec8e594 80 $rel_obj = $new->find_or_new_related($key, $rel_obj);
33dd4e80 81 }
2bc3c81e 82
83 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
84
de7c7c53 85 $new->set_from_related($key, $rel_obj);
86 $related->{$key} = $rel_obj;
61a622ee 87 next;
33dd4e80 88 } elsif ($info && $info->{attrs}{accessor}
89 && $info->{attrs}{accessor} eq 'multi'
90 && ref $attrs->{$key} eq 'ARRAY') {
2ec8e594 91 my $others = delete $attrs->{$key};
92 foreach my $rel_obj (@$others) {
93 if(!Scalar::Util::blessed($rel_obj)) {
94 $rel_obj = $new->new_related($key, $rel_obj);
95 $new->{_rel_in_storage} = 0;
33dd4e80 96 }
2bc3c81e 97
98 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
2ec8e594 99 }
100 $related->{$key} = $others;
101 next;
102 } elsif ($info && $info->{attrs}{accessor}
103 && $info->{attrs}{accessor} eq 'filter')
61a622ee 104 {
33dd4e80 105 ## 'filter' should disappear and get merged in with 'single' above!
2ec8e594 106 my $rel_obj = delete $attrs->{$key};
33dd4e80 107 if(!Scalar::Util::blessed($rel_obj)) {
df78aeb1 108 $rel_obj = $new->find_or_new_related($key, $rel_obj);
109 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
33dd4e80 110 }
111 $inflated->{$key} = $rel_obj;
61a622ee 112 next;
2ec8e594 113 } elsif ($class->has_column($key)
114 && $class->column_info($key)->{_inflate_info}) {
61a622ee 115 $inflated->{$key} = $attrs->{$key};
116 next;
117 }
118 }
119 $new->throw_exception("No such column $key on $class")
120 unless $class->has_column($key);
121 $new->store_column($key => $attrs->{$key});
7624b19f 122 }
f90375dd 123
61a622ee 124 $new->{_relationship_data} = $related if $related;
125 $new->{_inflated_column} = $inflated if $inflated;
7624b19f 126 }
04786a4c 127
7624b19f 128 return $new;
129}
130
8091aa91 131=head2 insert
7624b19f 132
133 $obj->insert;
134
b8810cc5 135Inserts an object into the database if it isn't already in
136there. Returns the object itself. Requires the object's result source to
137be set, or the class to have a result_source_instance method. To insert
138an entirely new object into the database, use C<create> (see
139L<DBIx::Class::ResultSet/create>).
7624b19f 140
264f1571 141This will also insert any uninserted, related objects held inside this
142one, see L<DBIx::Class::ResultSet/create> for more details.
143
7624b19f 144=cut
145
146sub insert {
147 my ($self) = @_;
148 return $self if $self->in_storage;
6aba697f 149 my $source = $self->result_source;
150 $source ||= $self->result_source($self->result_source_instance)
097d3227 151 if $self->can('result_source_instance');
aeb1bf75 152 $self->throw_exception("No result_source set on this object; can't insert")
153 unless $source;
6e399b4f 154
9c6d6d93 155 my $rollback_guard;
156
33dd4e80 157 # Check if we stored uninserted relobjs here in new()
33dd4e80 158 my %related_stuff = (%{$self->{_relationship_data} || {}},
159 %{$self->{_inflated_column} || {}});
9c6d6d93 160
ae66ef47 161 if(!$self->{_rel_in_storage}) {
8222f722 162
9c6d6d93 163 # The guard will save us if we blow out of this scope via die
1bc193ac 164 $rollback_guard = $source->storage->txn_scope_guard;
9c6d6d93 165
8222f722 166 ## Should all be in relationship_data, but we need to get rid of the
167 ## 'filter' reltype..
168 ## These are the FK rels, need their IDs for the insert.
9c6d6d93 169
170 my @pri = $self->primary_columns;
171
172 REL: foreach my $relname (keys %related_stuff) {
a8c98174 173
174 my $rel_obj = $related_stuff{$relname};
175
176 next REL unless (Scalar::Util::blessed($rel_obj)
177 && $rel_obj->isa('DBIx::Class::Row'));
178
179 my $cond = $source->relationship_info($relname)->{cond};
180
181 next REL unless ref($cond) eq 'HASH';
182
183 # map { foreign.foo => 'self.bar' } to { bar => 'foo' }
184
185 my $keyhash = { map { my $x = $_; $x =~ s/.*\.//; $x; } reverse %$cond };
9c6d6d93 186
187 # assume anything that references our PK probably is dependent on us
a8c98174 188 # rather than vice versa, unless the far side is (a) defined or (b)
189 # auto-increment
9c6d6d93 190
191 foreach my $p (@pri) {
a8c98174 192 if (exists $keyhash->{$p}) {
a8c98174 193 unless (defined($rel_obj->get_column($keyhash->{$p}))
194 || $rel_obj->column_info($keyhash->{$p})
195 ->{is_auto_increment}) {
196 next REL;
197 }
198 }
9c6d6d93 199 }
200
a8c98174 201 $rel_obj->insert();
202 $self->set_from_related($relname, $rel_obj);
203 delete $related_stuff{$relname};
33dd4e80 204 }
205 }
6e399b4f 206
7af8b477 207 $source->storage->insert($source, { $self->get_columns });
ac8e89d7 208
209 ## PK::Auto
3fda409f 210 my @auto_pri = grep {
211 !defined $self->get_column($_) ||
212 ref($self->get_column($_)) eq 'SCALAR'
213 } $self->primary_columns;
214
215 if (@auto_pri) {
216 #$self->throw_exception( "More than one possible key found for auto-inc on ".ref $self )
217 # if defined $too_many;
ac8e89d7 218
219 my $storage = $self->result_source->storage;
220 $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" )
221 unless $storage->can('last_insert_id');
3fda409f 222 my @ids = $storage->last_insert_id($self->result_source,@auto_pri);
223 $self->throw_exception( "Can't get last insert id" )
224 unless (@ids == @auto_pri);
225 $self->store_column($auto_pri[$_] => $ids[$_]) for 0 .. $#ids;
ac8e89d7 226 }
33dd4e80 227
ae66ef47 228 if(!$self->{_rel_in_storage}) {
8222f722 229 ## Now do the has_many rels, that need $selfs ID.
230 foreach my $relname (keys %related_stuff) {
9c6d6d93 231 my $rel_obj = $related_stuff{$relname};
232 my @cands;
233 if (Scalar::Util::blessed($rel_obj)
234 && $rel_obj->isa('DBIx::Class::Row')) {
235 @cands = ($rel_obj);
236 } elsif (ref $rel_obj eq 'ARRAY') {
237 @cands = @$rel_obj;
238 }
239 if (@cands) {
240 my $reverse = $source->reverse_relationship_info($relname);
241 foreach my $obj (@cands) {
242 $obj->set_from_related($_, $self) for keys %$reverse;
c193d1d2 243 $obj->insert() unless ($obj->in_storage || $obj->result_source->resultset->search({$obj->get_columns})->count);
8222f722 244 }
33dd4e80 245 }
246 }
1bc193ac 247 $rollback_guard->commit;
33dd4e80 248 }
33dd4e80 249
7624b19f 250 $self->in_storage(1);
251 $self->{_dirty_columns} = {};
64acc2bc 252 $self->{related_resultsets} = {};
729b29ae 253 undef $self->{_orig_ident};
7624b19f 254 return $self;
255}
256
8091aa91 257=head2 in_storage
7624b19f 258
259 $obj->in_storage; # Get value
260 $obj->in_storage(1); # Set value
261
264f1571 262Indicates whether the object exists as a row in the database or not
7624b19f 263
264=cut
265
266sub in_storage {
267 my ($self, $val) = @_;
268 $self->{_in_storage} = $val if @_ > 1;
269 return $self->{_in_storage};
270}
271
8091aa91 272=head2 update
7624b19f 273
d5d833d9 274 $obj->update \%columns?;
7624b19f 275
276Must be run on an object that is already in the database; issues an SQL
d3b0e369 277UPDATE query to commit any changes to the object to the database if
278required.
7624b19f 279
d5d833d9 280Also takes an options hashref of C<< column_name => value> pairs >> to update
f7043881 281first. But be aware that the hashref will be passed to
bacf6f12 282C<set_inflated_columns>, which might edit it in place, so dont rely on it being
283the same after a call to C<update>. If you need to preserve the hashref, it is
284sufficient to pass a shallow copy to C<update>, e.g. ( { %{ $href } } )
d5d833d9 285
7624b19f 286=cut
287
288sub update {
289 my ($self, $upd) = @_;
701da8c4 290 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 291 my $ident_cond = $self->ident_condition;
292 $self->throw_exception("Cannot safely update a row in a PK-less table")
293 if ! keys %$ident_cond;
6e399b4f 294
bacf6f12 295 $self->set_inflated_columns($upd) if $upd;
5a9e0e60 296 my %to_update = $self->get_dirty_columns;
297 return $self unless keys %to_update;
88cb6a1d 298 my $rows = $self->result_source->storage->update(
f4afcd5d 299 $self->result_source, \%to_update,
300 $self->{_orig_ident} || $ident_cond
301 );
7624b19f 302 if ($rows == 0) {
701da8c4 303 $self->throw_exception( "Can't update ${self}: row not found" );
7624b19f 304 } elsif ($rows > 1) {
701da8c4 305 $self->throw_exception("Can't update ${self}: updated more than one row");
7624b19f 306 }
307 $self->{_dirty_columns} = {};
64acc2bc 308 $self->{related_resultsets} = {};
729b29ae 309 undef $self->{_orig_ident};
7624b19f 310 return $self;
311}
312
8091aa91 313=head2 delete
7624b19f 314
315 $obj->delete
316
b8810cc5 317Deletes the object from the database. The object is still perfectly
61a622ee 318usable, but C<< ->in_storage() >> will now return 0 and the object must
319reinserted using C<< ->insert() >> before C<< ->update() >> can be used
b8810cc5 320on it. If you delete an object in a class with a C<has_many>
321relationship, all the related objects will be deleted as well. To turn
977e7403 322this behavior off, pass C<< cascade_delete => 0 >> in the C<$attr>
b8810cc5 323hashref. Any database-level cascade or restrict will take precedence
324over a DBIx-Class-based cascading delete. See also L<DBIx::Class::ResultSet/delete>.
7624b19f 325
326=cut
327
328sub delete {
329 my $self = shift;
330 if (ref $self) {
701da8c4 331 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 332 my $ident_cond = $self->ident_condition;
333 $self->throw_exception("Cannot safely delete a row in a PK-less table")
334 if ! keys %$ident_cond;
e0f56292 335 foreach my $column (keys %$ident_cond) {
75d07914 336 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
337 unless exists $self->{_column_data}{$column};
e0f56292 338 }
88cb6a1d 339 $self->result_source->storage->delete(
7af8b477 340 $self->result_source, $ident_cond);
7624b19f 341 $self->in_storage(undef);
7624b19f 342 } else {
701da8c4 343 $self->throw_exception("Can't do class delete without a ResultSource instance")
097d3227 344 unless $self->can('result_source_instance');
aeb1bf75 345 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
346 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
097d3227 347 $self->result_source_instance->resultset->search(@_)->delete;
7624b19f 348 }
349 return $self;
350}
351
8091aa91 352=head2 get_column
7624b19f 353
354 my $val = $obj->get_column($col);
355
61a622ee 356Gets a column value from a row object. Does not do any queries; the column
357must have already been fetched from the database and stored in the object. If
358there is an inflated value stored that has not yet been deflated, it is deflated
359when the method is invoked.
7624b19f 360
361=cut
362
363sub get_column {
364 my ($self, $column) = @_;
701da8c4 365 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
aeb1bf75 366 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
61a622ee 367 if (exists $self->{_inflated_column}{$column}) {
368 return $self->store_column($column,
369 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
370 }
701da8c4 371 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
7624b19f 372 return undef;
373}
374
9b83fccd 375=head2 has_column_loaded
376
377 if ( $obj->has_column_loaded($col) ) {
378 print "$col has been loaded from db";
379 }
380
381Returns a true value if the column value has been loaded from the
382database (or set locally).
383
384=cut
385
def81720 386sub has_column_loaded {
387 my ($self, $column) = @_;
388 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
61a622ee 389 return 1 if exists $self->{_inflated_column}{$column};
aeb1bf75 390 return exists $self->{_column_data}{$column};
def81720 391}
392
8091aa91 393=head2 get_columns
076a6864 394
395 my %data = $obj->get_columns;
396
8091aa91 397Does C<get_column>, for all column values at once.
076a6864 398
399=cut
400
401sub get_columns {
402 my $self = shift;
61a622ee 403 if (exists $self->{_inflated_column}) {
404 foreach my $col (keys %{$self->{_inflated_column}}) {
405 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
c4a30d56 406 unless exists $self->{_column_data}{$col};
61a622ee 407 }
408 }
cb5f2eea 409 return %{$self->{_column_data}};
d7156e50 410}
411
412=head2 get_dirty_columns
413
414 my %data = $obj->get_dirty_columns;
415
416Identical to get_columns but only returns those that have been changed.
417
418=cut
419
420sub get_dirty_columns {
421 my $self = shift;
422 return map { $_ => $self->{_column_data}{$_} }
423 keys %{$self->{_dirty_columns}};
076a6864 424}
425
ba4a6453 426=head2 get_inflated_columns
427
428 my $inflated_data = $obj->get_inflated_columns;
429
430Similar to get_columns but objects are returned for inflated columns instead of their raw non-inflated values.
431
432=cut
433
434sub get_inflated_columns {
435 my $self = shift;
436 return map {
437 my $accessor = $self->column_info($_)->{'accessor'} || $_;
438 ($_ => $self->$accessor);
439 } $self->columns;
440}
441
8091aa91 442=head2 set_column
7624b19f 443
444 $obj->set_column($col => $val);
445
8091aa91 446Sets a column value. If the new value is different from the old one,
447the column is marked as dirty for when you next call $obj->update.
7624b19f 448
449=cut
450
451sub set_column {
452 my $self = shift;
453 my ($column) = @_;
729b29ae 454 $self->{_orig_ident} ||= $self->ident_condition;
7624b19f 455 my $old = $self->get_column($column);
456 my $ret = $self->store_column(@_);
87772e46 457 $self->{_dirty_columns}{$column} = 1
458 if (defined $old ^ defined $ret) || (defined $old && $old ne $ret);
7624b19f 459 return $ret;
460}
461
8091aa91 462=head2 set_columns
076a6864 463
dc818523 464 my $copy = $orig->set_columns({ $col => $val, ... });
076a6864 465
8091aa91 466Sets more than one column value at once.
076a6864 467
468=cut
469
470sub set_columns {
471 my ($self,$data) = @_;
a2ca474b 472 foreach my $col (keys %$data) {
473 $self->set_column($col,$data->{$col});
076a6864 474 }
c01ab172 475 return $self;
076a6864 476}
477
bacf6f12 478=head2 set_inflated_columns
479
480 my $copy = $orig->set_inflated_columns({ $col => $val, $rel => $obj, ... });
481
482Sets more than one column value at once, taking care to respect inflations and
483relationships if relevant. Be aware that this hashref might be edited in place,
484so dont rely on it being the same after a call to C<set_inflated_columns>. If
485you need to preserve the hashref, it is sufficient to pass a shallow copy to
486C<set_inflated_columns>, e.g. ( { %{ $href } } )
487
488=cut
489
490sub set_inflated_columns {
491 my ( $self, $upd ) = @_;
492 foreach my $key (keys %$upd) {
493 if (ref $upd->{$key}) {
494 my $info = $self->relationship_info($key);
495 if ($info && $info->{attrs}{accessor}
496 && $info->{attrs}{accessor} eq 'single')
497 {
498 my $rel = delete $upd->{$key};
499 $self->set_from_related($key => $rel);
500 $self->{_relationship_data}{$key} = $rel;
501 } elsif ($info && $info->{attrs}{accessor}
502 && $info->{attrs}{accessor} eq 'multi'
503 && ref $upd->{$key} eq 'ARRAY') {
504 my $others = delete $upd->{$key};
505 foreach my $rel_obj (@$others) {
506 if(!Scalar::Util::blessed($rel_obj)) {
507 $rel_obj = $self->create_related($key, $rel_obj);
508 }
509 }
510 $self->{_relationship_data}{$key} = $others;
511# $related->{$key} = $others;
512 next;
513 }
514 elsif ($self->has_column($key)
515 && exists $self->column_info($key)->{_inflate_info})
516 {
517 $self->set_inflated_column($key, delete $upd->{$key});
518 }
519 }
520 }
521 $self->set_columns($upd);
522}
523
8091aa91 524=head2 copy
076a6864 525
526 my $copy = $orig->copy({ change => $to, ... });
527
8091aa91 528Inserts a new row with the specified changes.
076a6864 529
530=cut
531
c01ab172 532sub copy {
533 my ($self, $changes) = @_;
333cce60 534 $changes ||= {};
fde6e28e 535 my $col_data = { %{$self->{_column_data}} };
536 foreach my $col (keys %$col_data) {
537 delete $col_data->{$col}
538 if $self->result_source->column_info($col)->{is_auto_increment};
539 }
04786a4c 540
541 my $new = { _column_data => $col_data };
542 bless $new, ref $self;
543
83419ec6 544 $new->result_source($self->result_source);
bacf6f12 545 $new->set_inflated_columns($changes);
333cce60 546 $new->insert;
35688220 547
548 # Its possible we'll have 2 relations to the same Source. We need to make
549 # sure we don't try to insert the same row twice esle we'll violate unique
550 # constraints
551 my $rels_copied = {};
552
333cce60 553 foreach my $rel ($self->result_source->relationships) {
554 my $rel_info = $self->result_source->relationship_info($rel);
35688220 555
556 next unless $rel_info->{attrs}{cascade_copy};
557
558 my $resolved = $self->result_source->resolve_condition(
559 $rel_info->{cond}, $rel, $new
560 );
561
562 my $copied = $rels_copied->{ $rel_info->{source} } ||= {};
563 foreach my $related ($self->search_related($rel)) {
564 my $id_str = join("\0", $related->id);
565 next if $copied->{$id_str};
566 $copied->{$id_str} = 1;
567 my $rel_copy = $related->copy($resolved);
333cce60 568 }
35688220 569
333cce60 570 }
2c4c67b6 571 return $new;
c01ab172 572}
573
8091aa91 574=head2 store_column
7624b19f 575
576 $obj->store_column($col => $val);
577
8091aa91 578Sets a column value without marking it as dirty.
7624b19f 579
580=cut
581
582sub store_column {
583 my ($self, $column, $value) = @_;
75d07914 584 $self->throw_exception( "No such column '${column}'" )
d7156e50 585 unless exists $self->{_column_data}{$column} || $self->has_column($column);
75d07914 586 $self->throw_exception( "set_column called for ${column} without value" )
7624b19f 587 if @_ < 3;
588 return $self->{_column_data}{$column} = $value;
589}
590
b52e9bf8 591=head2 inflate_result
592
c01ab172 593 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 594
595Called by ResultSet to inflate a result from storage
596
597=cut
598
599sub inflate_result {
c01ab172 600 my ($class, $source, $me, $prefetch) = @_;
aec3eff1 601
602 my ($source_handle) = $source;
603
604 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
605 $source = $source_handle->resolve
606 } else {
607 $source_handle = $source->handle
608 }
609
04786a4c 610 my $new = {
aec3eff1 611 _source_handle => $source_handle,
04786a4c 612 _column_data => $me,
613 _in_storage => 1
614 };
615 bless $new, (ref $class || $class);
616
7fb16f1a 617 my $schema;
64acc2bc 618 foreach my $pre (keys %{$prefetch||{}}) {
619 my $pre_val = $prefetch->{$pre};
f9cc31dd 620 my $pre_source = $source->related_source($pre);
a86b1efe 621 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
622 unless $pre_source;
0f66a01b 623 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
a86b1efe 624 my @pre_objects;
625 foreach my $pre_rec (@$pre_val) {
75d07914 626 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
5a5bec6c 627 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
a86b1efe 628 next;
629 }
630 push(@pre_objects, $pre_source->result_class->inflate_result(
631 $pre_source, @{$pre_rec}));
632 }
633 $new->related_resultset($pre)->set_cache(\@pre_objects);
62e87ea8 634 } elsif (defined $pre_val->[0]) {
a86b1efe 635 my $fetched;
75d07914 636 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
a86b1efe 637 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
638 {
639 $fetched = $pre_source->result_class->inflate_result(
75d07914 640 $pre_source, @{$pre_val});
a86b1efe 641 }
9809a6df 642 $new->related_resultset($pre)->set_cache([ $fetched ]);
a86b1efe 643 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
644 $class->throw_exception("No accessor for prefetched $pre")
645 unless defined $accessor;
646 if ($accessor eq 'single') {
647 $new->{_relationship_data}{$pre} = $fetched;
648 } elsif ($accessor eq 'filter') {
649 $new->{_inflated_column}{$pre} = $fetched;
650 } else {
651 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
652 }
b52e9bf8 653 }
654 }
7624b19f 655 return $new;
656}
657
9b465d00 658=head2 update_or_insert
7624b19f 659
9b465d00 660 $obj->update_or_insert
7624b19f 661
8091aa91 662Updates the object if it's already in the db, else inserts it.
7624b19f 663
9b83fccd 664=head2 insert_or_update
665
666 $obj->insert_or_update
667
668Alias for L</update_or_insert>
669
7624b19f 670=cut
671
9b465d00 672*insert_or_update = \&update_or_insert;
673sub update_or_insert {
7624b19f 674 my $self = shift;
675 return ($self->in_storage ? $self->update : $self->insert);
676}
677
8091aa91 678=head2 is_changed
7624b19f 679
228dbcb4 680 my @changed_col_names = $obj->is_changed();
681 if ($obj->is_changed()) { ... }
7624b19f 682
9b83fccd 683In array context returns a list of columns with uncommited changes, or
684in scalar context returns a true value if there are uncommitted
685changes.
686
7624b19f 687=cut
688
689sub is_changed {
690 return keys %{shift->{_dirty_columns} || {}};
691}
228dbcb4 692
693=head2 is_column_changed
694
695 if ($obj->is_column_changed('col')) { ... }
696
9b83fccd 697Returns a true value if the column has uncommitted changes.
698
228dbcb4 699=cut
700
701sub is_column_changed {
702 my( $self, $col ) = @_;
703 return exists $self->{_dirty_columns}->{$col};
704}
7624b19f 705
097d3227 706=head2 result_source
707
9b83fccd 708 my $resultsource = $object->result_source;
097d3227 709
9b83fccd 710Accessor to the ResultSource this object was created from
87c4e602 711
aec3eff1 712=cut
713
714sub result_source {
715 my $self = shift;
716
717 if (@_) {
718 $self->_source_handle($_[0]->handle);
719 } else {
720 $self->_source_handle->resolve;
721 }
722}
723
9b83fccd 724=head2 register_column
27f01d1f 725
9b83fccd 726 $column_info = { .... };
727 $class->register_column($column_name, $column_info);
27f01d1f 728
9b83fccd 729Registers a column on the class. If the column_info has an 'accessor'
730key, creates an accessor named after the value if defined; if there is
731no such key, creates an accessor with the same name as the column
1f23a877 732
9b83fccd 733The column_info attributes are described in
734L<DBIx::Class::ResultSource/add_columns>
1f23a877 735
097d3227 736=cut
737
1f23a877 738sub register_column {
739 my ($class, $col, $info) = @_;
91b0fbd7 740 my $acc = $col;
741 if (exists $info->{accessor}) {
742 return unless defined $info->{accessor};
743 $acc = [ $info->{accessor}, $col ];
744 }
745 $class->mk_group_accessors('column' => $acc);
1f23a877 746}
747
701da8c4 748
5160b401 749=head2 throw_exception
701da8c4 750
751See Schema's throw_exception.
752
753=cut
754
755sub throw_exception {
756 my $self=shift;
66cab05c 757 if (ref $self && ref $self->result_source && $self->result_source->schema) {
701da8c4 758 $self->result_source->schema->throw_exception(@_);
759 } else {
760 croak(@_);
761 }
762}
763
33cf6616 764=head2 id
765
766Returns the primary key(s) for a row. Can't be called as a class method.
f7043881 767Actually implemented in L<DBIx::Class::PK>
33cf6616 768
769=head2 discard_changes
770
771Re-selects the row from the database, losing any changes that had
772been made.
773
774This method can also be used to refresh from storage, retrieving any
775changes made since the row was last read from storage. Actually
f7043881 776implemented in L<DBIx::Class::PK>
33cf6616 777
778=cut
779
7624b19f 7801;
781
7624b19f 782=head1 AUTHORS
783
daec44b8 784Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 785
786=head1 LICENSE
787
788You may distribute this code under the same terms as Perl itself.
789
790=cut