Merge 'DBIx-Class-current' into 'bulk_create'
[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 ();
1edd1722 9
aec3eff1 10__PACKAGE__->mk_group_accessors('simple' => qw/_source_handle/);
8c49f629 11
75d07914 12=head1 NAME
7624b19f 13
14DBIx::Class::Row - Basic row methods
15
16=head1 SYNOPSIS
17
18=head1 DESCRIPTION
19
20This class is responsible for defining and doing basic operations on rows
1ea77c14 21derived from L<DBIx::Class::ResultSource> objects.
7624b19f 22
23=head1 METHODS
24
8091aa91 25=head2 new
7624b19f 26
27 my $obj = My::Class->new($attrs);
28
29Creates a new row object from column => value mappings passed as a hash ref
30
33dd4e80 31Passing an object, or an arrayref of objects as a value will call
32L<DBIx::Class::Relationship::Base/set_from_related> for you. When
33passed a hashref or an arrayref of hashrefs as the value, these will
34be turned into objects via new_related, and treated as if you had
35passed objects.
36
7624b19f 37=cut
38
33dd4e80 39## NB (JER) - this assumes set_from_related can cope with multi-rels
40## 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().
41## This only works because DBIC doesnt yet care to check whether the new_related objects have been passed all their mandatory columns
42## When doing the later insert, we need to make sure the PKs are set.
43## using _relationship_data in new and funky ways..
44## check Relationship::CascadeActions and Relationship::Accessor for compat
45## tests!
46
7624b19f 47sub new {
61354236 48 my ($class, $attrs, $source) = @_;
7624b19f 49 $class = ref $class if ref $class;
04786a4c 50
51 my $new = { _column_data => {} };
52 bless $new, $class;
53
a6a280b9 54 $new->_source_handle($source) if $source;
55
7624b19f 56 if ($attrs) {
27f01d1f 57 $new->throw_exception("attrs must be a hashref")
58 unless ref($attrs) eq 'HASH';
61a622ee 59
60 my ($related,$inflated);
61 foreach my $key (keys %$attrs) {
62 if (ref $attrs->{$key}) {
63 my $info = $class->relationship_info($key);
64 if ($info && $info->{attrs}{accessor}
c4a30d56 65 && $info->{attrs}{accessor} eq 'single')
61a622ee 66 {
33dd4e80 67 my $rel_obj = $attrs->{$key};
68 $new->{_rel_in_storage} = 1;
69 if(!Scalar::Util::blessed($rel_obj)) {
70 $rel_obj = $new->new_related($key, $rel_obj);
71 $new->{_rel_in_storage} = 0;
72 }
61a622ee 73 $new->set_from_related($key, $attrs->{$key});
74 $related->{$key} = $attrs->{$key};
75 next;
33dd4e80 76 } elsif ($info && $info->{attrs}{accessor}
77 && $info->{attrs}{accessor} eq 'multi'
78 && ref $attrs->{$key} eq 'ARRAY') {
79 my $others = $attrs->{$key};
80 $new->{_rel_in_storage} = 1;
81 foreach my $rel_obj (@$others) {
82 if(!Scalar::Util::blessed($rel_obj)) {
83 $rel_obj = $new->new_related($key, $rel_obj);
84 $new->{_rel_in_storage} = 0;
85 }
86 }
87 $new->set_from_related($key, $others);
88 $related->{$key} = $attrs->{$key};
89 } elsif ($class->has_column($key)
61a622ee 90 && exists $class->column_info($key)->{_inflate_info})
91 {
33dd4e80 92 ## 'filter' should disappear and get merged in with 'single' above!
93 my $rel_obj = $attrs->{$key};
94 $new->{_rel_in_storage} = 1;
95 if(!Scalar::Util::blessed($rel_obj)) {
96 $rel_obj = $new->new_related($key, $rel_obj);
97 $new->{_rel_in_storage} = 0;
98 }
99 $inflated->{$key} = $rel_obj;
61a622ee 100 next;
101 }
102 }
103 $new->throw_exception("No such column $key on $class")
104 unless $class->has_column($key);
105 $new->store_column($key => $attrs->{$key});
7624b19f 106 }
f90375dd 107 if (my $source = delete $attrs->{-result_source}) {
108 $new->result_source($source);
7624b19f 109 }
f90375dd 110
61a622ee 111 $new->{_relationship_data} = $related if $related;
112 $new->{_inflated_column} = $inflated if $inflated;
7624b19f 113 }
04786a4c 114
7624b19f 115 return $new;
116}
117
8091aa91 118=head2 insert
7624b19f 119
120 $obj->insert;
121
b8810cc5 122Inserts an object into the database if it isn't already in
123there. Returns the object itself. Requires the object's result source to
124be set, or the class to have a result_source_instance method. To insert
125an entirely new object into the database, use C<create> (see
126L<DBIx::Class::ResultSet/create>).
7624b19f 127
128=cut
129
130sub insert {
131 my ($self) = @_;
132 return $self if $self->in_storage;
6aba697f 133 my $source = $self->result_source;
134 $source ||= $self->result_source($self->result_source_instance)
097d3227 135 if $self->can('result_source_instance');
aeb1bf75 136 $self->throw_exception("No result_source set on this object; can't insert")
137 unless $source;
6e399b4f 138
33dd4e80 139 # Check if we stored uninserted relobjs here in new()
140 $source->storage->txn_begin if(!$self->{_rel_in_storage});
141
142 my %related_stuff = (%{$self->{_relationship_data} || {}},
143 %{$self->{_inflated_column} || {}});
144 ## Should all be in relationship_data, but we need to get rid of the
145 ## 'filter' reltype..
146 foreach my $relname (keys %related_stuff) {
147 my $relobj = $related_stuff{$relname};
148 if(ref $relobj ne 'ARRAY') {
149 $relobj->insert() if(!$relobj->in_storage);
150 $self->set_from_related($relname, $relobj);
151 }
152 }
153
097d3227 154 $source->storage->insert($source->from, { $self->get_columns });
33dd4e80 155
156 foreach my $relname (keys %related_stuff) {
157 my $relobj = $related_stuff{$relname};
158 if(ref $relobj eq 'ARRAY') {
159 foreach my $obj (@$relobj) {
160 my $info = $self->relationship_info($relname);
161 ## What about multi-col FKs ?
162 my $key = $1 if($info && (keys %{$info->{cond}})[0] =~ /^foreign\.(\w+)/);
163 $obj->set_from_related($key, $self);
164 $obj->insert() if(!$obj->in_storage);
165 }
166 }
167 }
168 $source->storage->txn_commit if(!$self->{_rel_in_storage});
169
7624b19f 170 $self->in_storage(1);
171 $self->{_dirty_columns} = {};
64acc2bc 172 $self->{related_resultsets} = {};
729b29ae 173 undef $self->{_orig_ident};
7624b19f 174 return $self;
175}
176
8091aa91 177=head2 in_storage
7624b19f 178
179 $obj->in_storage; # Get value
180 $obj->in_storage(1); # Set value
181
182Indicated whether the object exists as a row in the database or not
183
184=cut
185
186sub in_storage {
187 my ($self, $val) = @_;
188 $self->{_in_storage} = $val if @_ > 1;
189 return $self->{_in_storage};
190}
191
8091aa91 192=head2 update
7624b19f 193
194 $obj->update;
195
196Must be run on an object that is already in the database; issues an SQL
d3b0e369 197UPDATE query to commit any changes to the object to the database if
198required.
7624b19f 199
200=cut
201
202sub update {
203 my ($self, $upd) = @_;
701da8c4 204 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 205 my $ident_cond = $self->ident_condition;
206 $self->throw_exception("Cannot safely update a row in a PK-less table")
207 if ! keys %$ident_cond;
6e399b4f 208
61a622ee 209 if ($upd) {
210 foreach my $key (keys %$upd) {
211 if (ref $upd->{$key}) {
212 my $info = $self->relationship_info($key);
213 if ($info && $info->{attrs}{accessor}
214 && $info->{attrs}{accessor} eq 'single')
215 {
216 my $rel = delete $upd->{$key};
217 $self->set_from_related($key => $rel);
218 $self->{_relationship_data}{$key} = $rel;
219 }
220 elsif ($self->has_column($key)
221 && exists $self->column_info($key)->{_inflate_info})
222 {
223 $self->set_inflated_column($key, delete $upd->{$key});
224 }
225 }
226 }
227 $self->set_columns($upd);
228 }
5a9e0e60 229 my %to_update = $self->get_dirty_columns;
230 return $self unless keys %to_update;
88cb6a1d 231 my $rows = $self->result_source->storage->update(
f4afcd5d 232 $self->result_source, \%to_update,
233 $self->{_orig_ident} || $ident_cond
234 );
7624b19f 235 if ($rows == 0) {
701da8c4 236 $self->throw_exception( "Can't update ${self}: row not found" );
7624b19f 237 } elsif ($rows > 1) {
701da8c4 238 $self->throw_exception("Can't update ${self}: updated more than one row");
7624b19f 239 }
240 $self->{_dirty_columns} = {};
64acc2bc 241 $self->{related_resultsets} = {};
729b29ae 242 undef $self->{_orig_ident};
7624b19f 243 return $self;
244}
245
8091aa91 246=head2 delete
7624b19f 247
248 $obj->delete
249
b8810cc5 250Deletes the object from the database. The object is still perfectly
61a622ee 251usable, but C<< ->in_storage() >> will now return 0 and the object must
252reinserted using C<< ->insert() >> before C<< ->update() >> can be used
b8810cc5 253on it. If you delete an object in a class with a C<has_many>
254relationship, all the related objects will be deleted as well. To turn
255this behavior off, pass C<cascade_delete => 0> in the C<$attr>
256hashref. Any database-level cascade or restrict will take precedence
257over a DBIx-Class-based cascading delete. See also L<DBIx::Class::ResultSet/delete>.
7624b19f 258
259=cut
260
261sub delete {
262 my $self = shift;
263 if (ref $self) {
701da8c4 264 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 265 my $ident_cond = $self->ident_condition;
266 $self->throw_exception("Cannot safely delete a row in a PK-less table")
267 if ! keys %$ident_cond;
e0f56292 268 foreach my $column (keys %$ident_cond) {
75d07914 269 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
270 unless exists $self->{_column_data}{$column};
e0f56292 271 }
88cb6a1d 272 $self->result_source->storage->delete(
7af8b477 273 $self->result_source, $ident_cond);
7624b19f 274 $self->in_storage(undef);
7624b19f 275 } else {
701da8c4 276 $self->throw_exception("Can't do class delete without a ResultSource instance")
097d3227 277 unless $self->can('result_source_instance');
aeb1bf75 278 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
279 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
097d3227 280 $self->result_source_instance->resultset->search(@_)->delete;
7624b19f 281 }
282 return $self;
283}
284
8091aa91 285=head2 get_column
7624b19f 286
287 my $val = $obj->get_column($col);
288
61a622ee 289Gets a column value from a row object. Does not do any queries; the column
290must have already been fetched from the database and stored in the object. If
291there is an inflated value stored that has not yet been deflated, it is deflated
292when the method is invoked.
7624b19f 293
294=cut
295
296sub get_column {
297 my ($self, $column) = @_;
701da8c4 298 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
aeb1bf75 299 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
61a622ee 300 if (exists $self->{_inflated_column}{$column}) {
301 return $self->store_column($column,
302 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
303 }
701da8c4 304 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
7624b19f 305 return undef;
306}
307
9b83fccd 308=head2 has_column_loaded
309
310 if ( $obj->has_column_loaded($col) ) {
311 print "$col has been loaded from db";
312 }
313
314Returns a true value if the column value has been loaded from the
c4a30d56 315database (or set locally).
9b83fccd 316
317=cut
318
def81720 319sub has_column_loaded {
320 my ($self, $column) = @_;
321 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
61a622ee 322 return 1 if exists $self->{_inflated_column}{$column};
aeb1bf75 323 return exists $self->{_column_data}{$column};
def81720 324}
325
8091aa91 326=head2 get_columns
076a6864 327
328 my %data = $obj->get_columns;
329
8091aa91 330Does C<get_column>, for all column values at once.
076a6864 331
332=cut
333
334sub get_columns {
335 my $self = shift;
61a622ee 336 if (exists $self->{_inflated_column}) {
337 foreach my $col (keys %{$self->{_inflated_column}}) {
338 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
c4a30d56 339 unless exists $self->{_column_data}{$col};
61a622ee 340 }
341 }
cb5f2eea 342 return %{$self->{_column_data}};
d7156e50 343}
344
345=head2 get_dirty_columns
346
347 my %data = $obj->get_dirty_columns;
348
349Identical to get_columns but only returns those that have been changed.
350
351=cut
352
353sub get_dirty_columns {
354 my $self = shift;
355 return map { $_ => $self->{_column_data}{$_} }
356 keys %{$self->{_dirty_columns}};
076a6864 357}
358
8091aa91 359=head2 set_column
7624b19f 360
361 $obj->set_column($col => $val);
362
8091aa91 363Sets a column value. If the new value is different from the old one,
364the column is marked as dirty for when you next call $obj->update.
7624b19f 365
366=cut
367
368sub set_column {
369 my $self = shift;
370 my ($column) = @_;
729b29ae 371 $self->{_orig_ident} ||= $self->ident_condition;
7624b19f 372 my $old = $self->get_column($column);
373 my $ret = $self->store_column(@_);
87772e46 374 $self->{_dirty_columns}{$column} = 1
375 if (defined $old ^ defined $ret) || (defined $old && $old ne $ret);
7624b19f 376 return $ret;
377}
378
8091aa91 379=head2 set_columns
076a6864 380
dc818523 381 my $copy = $orig->set_columns({ $col => $val, ... });
076a6864 382
8091aa91 383Sets more than one column value at once.
076a6864 384
385=cut
386
387sub set_columns {
388 my ($self,$data) = @_;
a2ca474b 389 foreach my $col (keys %$data) {
390 $self->set_column($col,$data->{$col});
076a6864 391 }
c01ab172 392 return $self;
076a6864 393}
394
8091aa91 395=head2 copy
076a6864 396
397 my $copy = $orig->copy({ change => $to, ... });
398
8091aa91 399Inserts a new row with the specified changes.
076a6864 400
401=cut
402
c01ab172 403sub copy {
404 my ($self, $changes) = @_;
333cce60 405 $changes ||= {};
fde6e28e 406 my $col_data = { %{$self->{_column_data}} };
407 foreach my $col (keys %$col_data) {
408 delete $col_data->{$col}
409 if $self->result_source->column_info($col)->{is_auto_increment};
410 }
04786a4c 411
412 my $new = { _column_data => $col_data };
413 bless $new, ref $self;
414
83419ec6 415 $new->result_source($self->result_source);
ecd1f408 416 $new->set_columns($changes);
333cce60 417 $new->insert;
418 foreach my $rel ($self->result_source->relationships) {
419 my $rel_info = $self->result_source->relationship_info($rel);
420 if ($rel_info->{attrs}{cascade_copy}) {
421 my $resolved = $self->result_source->resolve_condition(
422 $rel_info->{cond}, $rel, $new);
423 foreach my $related ($self->search_related($rel)) {
424 $related->copy($resolved);
425 }
426 }
427 }
2c4c67b6 428 return $new;
c01ab172 429}
430
8091aa91 431=head2 store_column
7624b19f 432
433 $obj->store_column($col => $val);
434
8091aa91 435Sets a column value without marking it as dirty.
7624b19f 436
437=cut
438
439sub store_column {
440 my ($self, $column, $value) = @_;
75d07914 441 $self->throw_exception( "No such column '${column}'" )
d7156e50 442 unless exists $self->{_column_data}{$column} || $self->has_column($column);
75d07914 443 $self->throw_exception( "set_column called for ${column} without value" )
7624b19f 444 if @_ < 3;
445 return $self->{_column_data}{$column} = $value;
446}
447
b52e9bf8 448=head2 inflate_result
449
c01ab172 450 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 451
452Called by ResultSet to inflate a result from storage
453
454=cut
455
456sub inflate_result {
c01ab172 457 my ($class, $source, $me, $prefetch) = @_;
aec3eff1 458
459 my ($source_handle) = $source;
460
461 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
462 $source = $source_handle->resolve
463 } else {
464 $source_handle = $source->handle
465 }
466
04786a4c 467 my $new = {
aec3eff1 468 _source_handle => $source_handle,
04786a4c 469 _column_data => $me,
470 _in_storage => 1
471 };
472 bless $new, (ref $class || $class);
473
7fb16f1a 474 my $schema;
64acc2bc 475 foreach my $pre (keys %{$prefetch||{}}) {
476 my $pre_val = $prefetch->{$pre};
f9cc31dd 477 my $pre_source = $source->related_source($pre);
a86b1efe 478 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
479 unless $pre_source;
0f66a01b 480 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
a86b1efe 481 my @pre_objects;
482 foreach my $pre_rec (@$pre_val) {
75d07914 483 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
5a5bec6c 484 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
a86b1efe 485 next;
486 }
487 push(@pre_objects, $pre_source->result_class->inflate_result(
488 $pre_source, @{$pre_rec}));
489 }
490 $new->related_resultset($pre)->set_cache(\@pre_objects);
62e87ea8 491 } elsif (defined $pre_val->[0]) {
a86b1efe 492 my $fetched;
75d07914 493 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
a86b1efe 494 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
495 {
496 $fetched = $pre_source->result_class->inflate_result(
75d07914 497 $pre_source, @{$pre_val});
a86b1efe 498 }
499 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
500 $class->throw_exception("No accessor for prefetched $pre")
501 unless defined $accessor;
502 if ($accessor eq 'single') {
503 $new->{_relationship_data}{$pre} = $fetched;
504 } elsif ($accessor eq 'filter') {
505 $new->{_inflated_column}{$pre} = $fetched;
506 } else {
507 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
508 }
b52e9bf8 509 }
510 }
7624b19f 511 return $new;
512}
513
9b465d00 514=head2 update_or_insert
7624b19f 515
9b465d00 516 $obj->update_or_insert
7624b19f 517
8091aa91 518Updates the object if it's already in the db, else inserts it.
7624b19f 519
9b83fccd 520=head2 insert_or_update
521
522 $obj->insert_or_update
523
524Alias for L</update_or_insert>
525
7624b19f 526=cut
527
9b465d00 528*insert_or_update = \&update_or_insert;
529sub update_or_insert {
7624b19f 530 my $self = shift;
531 return ($self->in_storage ? $self->update : $self->insert);
532}
533
8091aa91 534=head2 is_changed
7624b19f 535
228dbcb4 536 my @changed_col_names = $obj->is_changed();
537 if ($obj->is_changed()) { ... }
7624b19f 538
9b83fccd 539In array context returns a list of columns with uncommited changes, or
540in scalar context returns a true value if there are uncommitted
541changes.
542
7624b19f 543=cut
544
545sub is_changed {
546 return keys %{shift->{_dirty_columns} || {}};
547}
228dbcb4 548
549=head2 is_column_changed
550
551 if ($obj->is_column_changed('col')) { ... }
552
9b83fccd 553Returns a true value if the column has uncommitted changes.
554
228dbcb4 555=cut
556
557sub is_column_changed {
558 my( $self, $col ) = @_;
559 return exists $self->{_dirty_columns}->{$col};
560}
7624b19f 561
097d3227 562=head2 result_source
563
9b83fccd 564 my $resultsource = $object->result_source;
097d3227 565
9b83fccd 566Accessor to the ResultSource this object was created from
87c4e602 567
aec3eff1 568=cut
569
570sub result_source {
571 my $self = shift;
572
573 if (@_) {
574 $self->_source_handle($_[0]->handle);
575 } else {
576 $self->_source_handle->resolve;
577 }
578}
579
9b83fccd 580=head2 register_column
27f01d1f 581
9b83fccd 582 $column_info = { .... };
583 $class->register_column($column_name, $column_info);
27f01d1f 584
9b83fccd 585Registers a column on the class. If the column_info has an 'accessor'
586key, creates an accessor named after the value if defined; if there is
587no such key, creates an accessor with the same name as the column
1f23a877 588
9b83fccd 589The column_info attributes are described in
590L<DBIx::Class::ResultSource/add_columns>
1f23a877 591
097d3227 592=cut
593
1f23a877 594sub register_column {
595 my ($class, $col, $info) = @_;
91b0fbd7 596 my $acc = $col;
597 if (exists $info->{accessor}) {
598 return unless defined $info->{accessor};
599 $acc = [ $info->{accessor}, $col ];
600 }
601 $class->mk_group_accessors('column' => $acc);
1f23a877 602}
603
701da8c4 604
5160b401 605=head2 throw_exception
701da8c4 606
607See Schema's throw_exception.
608
609=cut
610
611sub throw_exception {
612 my $self=shift;
613 if (ref $self && ref $self->result_source) {
614 $self->result_source->schema->throw_exception(@_);
615 } else {
616 croak(@_);
617 }
618}
619
7624b19f 6201;
621
7624b19f 622=head1 AUTHORS
623
daec44b8 624Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 625
626=head1 LICENSE
627
628You may distribute this code under the same terms as Perl itself.
629
630=cut