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