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