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