test plan
[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 $source->storage->txn_begin;
163
9c6d6d93 164 # The guard will save us if we blow out of this scope via die
165
166 $rollback_guard = Scope::Guard->new(sub { $source->storage->txn_rollback });
167
8222f722 168 ## Should all be in relationship_data, but we need to get rid of the
169 ## 'filter' reltype..
170 ## These are the FK rels, need their IDs for the insert.
9c6d6d93 171
172 my @pri = $self->primary_columns;
173
174 REL: foreach my $relname (keys %related_stuff) {
a8c98174 175
176 my $rel_obj = $related_stuff{$relname};
177
178 next REL unless (Scalar::Util::blessed($rel_obj)
179 && $rel_obj->isa('DBIx::Class::Row'));
180
181 my $cond = $source->relationship_info($relname)->{cond};
182
183 next REL unless ref($cond) eq 'HASH';
184
185 # map { foreign.foo => 'self.bar' } to { bar => 'foo' }
186
187 my $keyhash = { map { my $x = $_; $x =~ s/.*\.//; $x; } reverse %$cond };
9c6d6d93 188
189 # assume anything that references our PK probably is dependent on us
a8c98174 190 # rather than vice versa, unless the far side is (a) defined or (b)
191 # auto-increment
9c6d6d93 192
193 foreach my $p (@pri) {
a8c98174 194 if (exists $keyhash->{$p}) {
a8c98174 195 unless (defined($rel_obj->get_column($keyhash->{$p}))
196 || $rel_obj->column_info($keyhash->{$p})
197 ->{is_auto_increment}) {
198 next REL;
199 }
200 }
9c6d6d93 201 }
202
a8c98174 203 $rel_obj->insert();
204 $self->set_from_related($relname, $rel_obj);
205 delete $related_stuff{$relname};
33dd4e80 206 }
207 }
6e399b4f 208
7af8b477 209 $source->storage->insert($source, { $self->get_columns });
ac8e89d7 210
211 ## PK::Auto
3fda409f 212 my @auto_pri = grep {
213 !defined $self->get_column($_) ||
214 ref($self->get_column($_)) eq 'SCALAR'
215 } $self->primary_columns;
216
217 if (@auto_pri) {
218 #$self->throw_exception( "More than one possible key found for auto-inc on ".ref $self )
219 # if defined $too_many;
ac8e89d7 220
221 my $storage = $self->result_source->storage;
222 $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" )
223 unless $storage->can('last_insert_id');
3fda409f 224 my @ids = $storage->last_insert_id($self->result_source,@auto_pri);
225 $self->throw_exception( "Can't get last insert id" )
226 unless (@ids == @auto_pri);
227 $self->store_column($auto_pri[$_] => $ids[$_]) for 0 .. $#ids;
ac8e89d7 228 }
33dd4e80 229
ae66ef47 230 if(!$self->{_rel_in_storage}) {
8222f722 231 ## Now do the has_many rels, that need $selfs ID.
232 foreach my $relname (keys %related_stuff) {
9c6d6d93 233 my $rel_obj = $related_stuff{$relname};
234 my @cands;
235 if (Scalar::Util::blessed($rel_obj)
236 && $rel_obj->isa('DBIx::Class::Row')) {
237 @cands = ($rel_obj);
238 } elsif (ref $rel_obj eq 'ARRAY') {
239 @cands = @$rel_obj;
240 }
241 if (@cands) {
242 my $reverse = $source->reverse_relationship_info($relname);
243 foreach my $obj (@cands) {
244 $obj->set_from_related($_, $self) for keys %$reverse;
c193d1d2 245 $obj->insert() unless ($obj->in_storage || $obj->result_source->resultset->search({$obj->get_columns})->count);
8222f722 246 }
33dd4e80 247 }
248 }
8222f722 249 $source->storage->txn_commit;
9c6d6d93 250 $rollback_guard->dismiss;
33dd4e80 251 }
33dd4e80 252
7624b19f 253 $self->in_storage(1);
254 $self->{_dirty_columns} = {};
64acc2bc 255 $self->{related_resultsets} = {};
729b29ae 256 undef $self->{_orig_ident};
7624b19f 257 return $self;
258}
259
8091aa91 260=head2 in_storage
7624b19f 261
262 $obj->in_storage; # Get value
263 $obj->in_storage(1); # Set value
264
264f1571 265Indicates whether the object exists as a row in the database or not
7624b19f 266
267=cut
268
269sub in_storage {
270 my ($self, $val) = @_;
271 $self->{_in_storage} = $val if @_ > 1;
272 return $self->{_in_storage};
273}
274
8091aa91 275=head2 update
7624b19f 276
d5d833d9 277 $obj->update \%columns?;
7624b19f 278
279Must be run on an object that is already in the database; issues an SQL
d3b0e369 280UPDATE query to commit any changes to the object to the database if
281required.
7624b19f 282
d5d833d9 283Also takes an options hashref of C<< column_name => value> pairs >> to update
284first. But be aware that this hashref might be edited in place, so dont rely on
8b621a87 285it being the same after a call to C<update>. If you need to preserve the hashref,
286it is sufficient to pass a shallow copy to C<update>, e.g. ( { %{ $href } } )
d5d833d9 287
7624b19f 288=cut
289
290sub update {
291 my ($self, $upd) = @_;
701da8c4 292 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 293 my $ident_cond = $self->ident_condition;
294 $self->throw_exception("Cannot safely update a row in a PK-less table")
295 if ! keys %$ident_cond;
6e399b4f 296
61a622ee 297 if ($upd) {
298 foreach my $key (keys %$upd) {
299 if (ref $upd->{$key}) {
300 my $info = $self->relationship_info($key);
301 if ($info && $info->{attrs}{accessor}
302 && $info->{attrs}{accessor} eq 'single')
303 {
304 my $rel = delete $upd->{$key};
305 $self->set_from_related($key => $rel);
306 $self->{_relationship_data}{$key} = $rel;
af2d42c0 307 } elsif ($info && $info->{attrs}{accessor}
308 && $info->{attrs}{accessor} eq 'multi'
309 && ref $upd->{$key} eq 'ARRAY') {
310 my $others = delete $upd->{$key};
311 foreach my $rel_obj (@$others) {
312 if(!Scalar::Util::blessed($rel_obj)) {
313 $rel_obj = $self->create_related($key, $rel_obj);
314 }
315 }
316 $self->{_relationship_data}{$key} = $others;
317# $related->{$key} = $others;
318 next;
319 }
61a622ee 320 elsif ($self->has_column($key)
321 && exists $self->column_info($key)->{_inflate_info})
322 {
323 $self->set_inflated_column($key, delete $upd->{$key});
324 }
325 }
326 }
327 $self->set_columns($upd);
328 }
5a9e0e60 329 my %to_update = $self->get_dirty_columns;
330 return $self unless keys %to_update;
88cb6a1d 331 my $rows = $self->result_source->storage->update(
f4afcd5d 332 $self->result_source, \%to_update,
333 $self->{_orig_ident} || $ident_cond
334 );
7624b19f 335 if ($rows == 0) {
701da8c4 336 $self->throw_exception( "Can't update ${self}: row not found" );
7624b19f 337 } elsif ($rows > 1) {
701da8c4 338 $self->throw_exception("Can't update ${self}: updated more than one row");
7624b19f 339 }
340 $self->{_dirty_columns} = {};
64acc2bc 341 $self->{related_resultsets} = {};
729b29ae 342 undef $self->{_orig_ident};
7624b19f 343 return $self;
344}
345
8091aa91 346=head2 delete
7624b19f 347
348 $obj->delete
349
b8810cc5 350Deletes the object from the database. The object is still perfectly
61a622ee 351usable, but C<< ->in_storage() >> will now return 0 and the object must
352reinserted using C<< ->insert() >> before C<< ->update() >> can be used
b8810cc5 353on it. If you delete an object in a class with a C<has_many>
354relationship, all the related objects will be deleted as well. To turn
977e7403 355this behavior off, pass C<< cascade_delete => 0 >> in the C<$attr>
b8810cc5 356hashref. Any database-level cascade or restrict will take precedence
357over a DBIx-Class-based cascading delete. See also L<DBIx::Class::ResultSet/delete>.
7624b19f 358
359=cut
360
361sub delete {
362 my $self = shift;
363 if (ref $self) {
701da8c4 364 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 365 my $ident_cond = $self->ident_condition;
366 $self->throw_exception("Cannot safely delete a row in a PK-less table")
367 if ! keys %$ident_cond;
e0f56292 368 foreach my $column (keys %$ident_cond) {
75d07914 369 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
370 unless exists $self->{_column_data}{$column};
e0f56292 371 }
88cb6a1d 372 $self->result_source->storage->delete(
7af8b477 373 $self->result_source, $ident_cond);
7624b19f 374 $self->in_storage(undef);
7624b19f 375 } else {
701da8c4 376 $self->throw_exception("Can't do class delete without a ResultSource instance")
097d3227 377 unless $self->can('result_source_instance');
aeb1bf75 378 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
379 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
097d3227 380 $self->result_source_instance->resultset->search(@_)->delete;
7624b19f 381 }
382 return $self;
383}
384
8091aa91 385=head2 get_column
7624b19f 386
387 my $val = $obj->get_column($col);
388
61a622ee 389Gets a column value from a row object. Does not do any queries; the column
390must have already been fetched from the database and stored in the object. If
391there is an inflated value stored that has not yet been deflated, it is deflated
392when the method is invoked.
7624b19f 393
394=cut
395
396sub get_column {
397 my ($self, $column) = @_;
701da8c4 398 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
aeb1bf75 399 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
61a622ee 400 if (exists $self->{_inflated_column}{$column}) {
401 return $self->store_column($column,
402 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
403 }
701da8c4 404 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
7624b19f 405 return undef;
406}
407
9b83fccd 408=head2 has_column_loaded
409
410 if ( $obj->has_column_loaded($col) ) {
411 print "$col has been loaded from db";
412 }
413
414Returns a true value if the column value has been loaded from the
415database (or set locally).
416
417=cut
418
def81720 419sub has_column_loaded {
420 my ($self, $column) = @_;
421 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
61a622ee 422 return 1 if exists $self->{_inflated_column}{$column};
aeb1bf75 423 return exists $self->{_column_data}{$column};
def81720 424}
425
8091aa91 426=head2 get_columns
076a6864 427
428 my %data = $obj->get_columns;
429
8091aa91 430Does C<get_column>, for all column values at once.
076a6864 431
432=cut
433
434sub get_columns {
435 my $self = shift;
61a622ee 436 if (exists $self->{_inflated_column}) {
437 foreach my $col (keys %{$self->{_inflated_column}}) {
438 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
c4a30d56 439 unless exists $self->{_column_data}{$col};
61a622ee 440 }
441 }
cb5f2eea 442 return %{$self->{_column_data}};
d7156e50 443}
444
445=head2 get_dirty_columns
446
447 my %data = $obj->get_dirty_columns;
448
449Identical to get_columns but only returns those that have been changed.
450
451=cut
452
453sub get_dirty_columns {
454 my $self = shift;
455 return map { $_ => $self->{_column_data}{$_} }
456 keys %{$self->{_dirty_columns}};
076a6864 457}
458
ba4a6453 459=head2 get_inflated_columns
460
461 my $inflated_data = $obj->get_inflated_columns;
462
463Similar to get_columns but objects are returned for inflated columns instead of their raw non-inflated values.
464
465=cut
466
467sub get_inflated_columns {
468 my $self = shift;
469 return map {
470 my $accessor = $self->column_info($_)->{'accessor'} || $_;
471 ($_ => $self->$accessor);
472 } $self->columns;
473}
474
8091aa91 475=head2 set_column
7624b19f 476
477 $obj->set_column($col => $val);
478
8091aa91 479Sets a column value. If the new value is different from the old one,
480the column is marked as dirty for when you next call $obj->update.
7624b19f 481
482=cut
483
484sub set_column {
485 my $self = shift;
486 my ($column) = @_;
729b29ae 487 $self->{_orig_ident} ||= $self->ident_condition;
7624b19f 488 my $old = $self->get_column($column);
489 my $ret = $self->store_column(@_);
87772e46 490 $self->{_dirty_columns}{$column} = 1
491 if (defined $old ^ defined $ret) || (defined $old && $old ne $ret);
7624b19f 492 return $ret;
493}
494
8091aa91 495=head2 set_columns
076a6864 496
dc818523 497 my $copy = $orig->set_columns({ $col => $val, ... });
076a6864 498
8091aa91 499Sets more than one column value at once.
076a6864 500
501=cut
502
503sub set_columns {
504 my ($self,$data) = @_;
a2ca474b 505 foreach my $col (keys %$data) {
506 $self->set_column($col,$data->{$col});
076a6864 507 }
c01ab172 508 return $self;
076a6864 509}
510
8091aa91 511=head2 copy
076a6864 512
513 my $copy = $orig->copy({ change => $to, ... });
514
8091aa91 515Inserts a new row with the specified changes.
076a6864 516
517=cut
518
c01ab172 519sub copy {
520 my ($self, $changes) = @_;
333cce60 521 $changes ||= {};
fde6e28e 522 my $col_data = { %{$self->{_column_data}} };
523 foreach my $col (keys %$col_data) {
524 delete $col_data->{$col}
525 if $self->result_source->column_info($col)->{is_auto_increment};
526 }
04786a4c 527
528 my $new = { _column_data => $col_data };
529 bless $new, ref $self;
530
83419ec6 531 $new->result_source($self->result_source);
ecd1f408 532 $new->set_columns($changes);
333cce60 533 $new->insert;
35688220 534
535 # Its possible we'll have 2 relations to the same Source. We need to make
536 # sure we don't try to insert the same row twice esle we'll violate unique
537 # constraints
538 my $rels_copied = {};
539
333cce60 540 foreach my $rel ($self->result_source->relationships) {
541 my $rel_info = $self->result_source->relationship_info($rel);
35688220 542
543 next unless $rel_info->{attrs}{cascade_copy};
544
545 my $resolved = $self->result_source->resolve_condition(
546 $rel_info->{cond}, $rel, $new
547 );
548
549 my $copied = $rels_copied->{ $rel_info->{source} } ||= {};
550 foreach my $related ($self->search_related($rel)) {
551 my $id_str = join("\0", $related->id);
552 next if $copied->{$id_str};
553 $copied->{$id_str} = 1;
554 my $rel_copy = $related->copy($resolved);
333cce60 555 }
35688220 556
333cce60 557 }
2c4c67b6 558 return $new;
c01ab172 559}
560
8091aa91 561=head2 store_column
7624b19f 562
563 $obj->store_column($col => $val);
564
8091aa91 565Sets a column value without marking it as dirty.
7624b19f 566
567=cut
568
569sub store_column {
570 my ($self, $column, $value) = @_;
75d07914 571 $self->throw_exception( "No such column '${column}'" )
d7156e50 572 unless exists $self->{_column_data}{$column} || $self->has_column($column);
75d07914 573 $self->throw_exception( "set_column called for ${column} without value" )
7624b19f 574 if @_ < 3;
575 return $self->{_column_data}{$column} = $value;
576}
577
b52e9bf8 578=head2 inflate_result
579
c01ab172 580 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 581
582Called by ResultSet to inflate a result from storage
583
584=cut
585
586sub inflate_result {
c01ab172 587 my ($class, $source, $me, $prefetch) = @_;
aec3eff1 588
589 my ($source_handle) = $source;
590
591 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
592 $source = $source_handle->resolve
593 } else {
594 $source_handle = $source->handle
595 }
596
04786a4c 597 my $new = {
aec3eff1 598 _source_handle => $source_handle,
04786a4c 599 _column_data => $me,
600 _in_storage => 1
601 };
602 bless $new, (ref $class || $class);
603
7fb16f1a 604 my $schema;
64acc2bc 605 foreach my $pre (keys %{$prefetch||{}}) {
606 my $pre_val = $prefetch->{$pre};
f9cc31dd 607 my $pre_source = $source->related_source($pre);
a86b1efe 608 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
609 unless $pre_source;
0f66a01b 610 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
a86b1efe 611 my @pre_objects;
612 foreach my $pre_rec (@$pre_val) {
75d07914 613 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
5a5bec6c 614 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
a86b1efe 615 next;
616 }
617 push(@pre_objects, $pre_source->result_class->inflate_result(
618 $pre_source, @{$pre_rec}));
619 }
620 $new->related_resultset($pre)->set_cache(\@pre_objects);
62e87ea8 621 } elsif (defined $pre_val->[0]) {
a86b1efe 622 my $fetched;
75d07914 623 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
a86b1efe 624 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
625 {
626 $fetched = $pre_source->result_class->inflate_result(
75d07914 627 $pre_source, @{$pre_val});
a86b1efe 628 }
9809a6df 629 $new->related_resultset($pre)->set_cache([ $fetched ]);
a86b1efe 630 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
631 $class->throw_exception("No accessor for prefetched $pre")
632 unless defined $accessor;
633 if ($accessor eq 'single') {
634 $new->{_relationship_data}{$pre} = $fetched;
635 } elsif ($accessor eq 'filter') {
636 $new->{_inflated_column}{$pre} = $fetched;
637 } else {
638 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
639 }
b52e9bf8 640 }
641 }
7624b19f 642 return $new;
643}
644
9b465d00 645=head2 update_or_insert
7624b19f 646
9b465d00 647 $obj->update_or_insert
7624b19f 648
8091aa91 649Updates the object if it's already in the db, else inserts it.
7624b19f 650
9b83fccd 651=head2 insert_or_update
652
653 $obj->insert_or_update
654
655Alias for L</update_or_insert>
656
7624b19f 657=cut
658
9b465d00 659*insert_or_update = \&update_or_insert;
660sub update_or_insert {
7624b19f 661 my $self = shift;
662 return ($self->in_storage ? $self->update : $self->insert);
663}
664
8091aa91 665=head2 is_changed
7624b19f 666
228dbcb4 667 my @changed_col_names = $obj->is_changed();
668 if ($obj->is_changed()) { ... }
7624b19f 669
9b83fccd 670In array context returns a list of columns with uncommited changes, or
671in scalar context returns a true value if there are uncommitted
672changes.
673
7624b19f 674=cut
675
676sub is_changed {
677 return keys %{shift->{_dirty_columns} || {}};
678}
228dbcb4 679
680=head2 is_column_changed
681
682 if ($obj->is_column_changed('col')) { ... }
683
9b83fccd 684Returns a true value if the column has uncommitted changes.
685
228dbcb4 686=cut
687
688sub is_column_changed {
689 my( $self, $col ) = @_;
690 return exists $self->{_dirty_columns}->{$col};
691}
7624b19f 692
097d3227 693=head2 result_source
694
9b83fccd 695 my $resultsource = $object->result_source;
097d3227 696
9b83fccd 697Accessor to the ResultSource this object was created from
87c4e602 698
aec3eff1 699=cut
700
701sub result_source {
702 my $self = shift;
703
704 if (@_) {
705 $self->_source_handle($_[0]->handle);
706 } else {
707 $self->_source_handle->resolve;
708 }
709}
710
9b83fccd 711=head2 register_column
27f01d1f 712
9b83fccd 713 $column_info = { .... };
714 $class->register_column($column_name, $column_info);
27f01d1f 715
9b83fccd 716Registers a column on the class. If the column_info has an 'accessor'
717key, creates an accessor named after the value if defined; if there is
718no such key, creates an accessor with the same name as the column
1f23a877 719
9b83fccd 720The column_info attributes are described in
721L<DBIx::Class::ResultSource/add_columns>
1f23a877 722
097d3227 723=cut
724
1f23a877 725sub register_column {
726 my ($class, $col, $info) = @_;
91b0fbd7 727 my $acc = $col;
728 if (exists $info->{accessor}) {
729 return unless defined $info->{accessor};
730 $acc = [ $info->{accessor}, $col ];
731 }
732 $class->mk_group_accessors('column' => $acc);
1f23a877 733}
734
701da8c4 735
5160b401 736=head2 throw_exception
701da8c4 737
738See Schema's throw_exception.
739
740=cut
741
742sub throw_exception {
743 my $self=shift;
66cab05c 744 if (ref $self && ref $self->result_source && $self->result_source->schema) {
701da8c4 745 $self->result_source->schema->throw_exception(@_);
746 } else {
747 croak(@_);
748 }
749}
750
7624b19f 7511;
752
7624b19f 753=head1 AUTHORS
754
daec44b8 755Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 756
757=head1 LICENSE
758
759You may distribute this code under the same terms as Perl itself.
760
761=cut