prevent objects implicitly passed via new_related having insertion cascaded to them...
[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
e0cdf2cb 11BEGIN {
12 *MULTICREATE_DEBUG =
13 $ENV{DBIC_MULTICREATE_DEBUG}
14 ? sub () { 1 }
15 : sub () { 0 };
16}
17
aec3eff1 18__PACKAGE__->mk_group_accessors('simple' => qw/_source_handle/);
8c49f629 19
75d07914 20=head1 NAME
7624b19f 21
22DBIx::Class::Row - Basic row methods
23
24=head1 SYNOPSIS
25
26=head1 DESCRIPTION
27
28This class is responsible for defining and doing basic operations on rows
1ea77c14 29derived from L<DBIx::Class::ResultSource> objects.
7624b19f 30
a2531bf2 31Row objects are returned from L<DBIx::Class::ResultSet>s using the
ea36f4e4 32L<create|DBIx::Class::ResultSet/create>, L<find|DBIx::Class::ResultSet/find>,
33L<next|DBIx::Class::ResultSet/next> and L<all|DBIx::Class::ResultSet/all> methods,
34as well as invocations of 'single' (
35L<belongs_to|DBIx::Class::Relationship/belongs_to>,
36L<has_one|DBIx::Class::Relationship/has_one> or
37L<might_have|DBIx::Class::Relationship/might_have>)
38relationship accessors of L<DBIx::Class::Row> objects.
a2531bf2 39
7624b19f 40=head1 METHODS
41
8091aa91 42=head2 new
7624b19f 43
a2531bf2 44 my $row = My::Class->new(\%attrs);
45
46 my $row = $schema->resultset('MySource')->new(\%colsandvalues);
47
48=over
49
50=item Arguments: \%attrs or \%colsandvalues
51
52=item Returns: A Row object
7624b19f 53
a2531bf2 54=back
55
56While you can create a new row object by calling C<new> directly on
57this class, you are better off calling it on a
58L<DBIx::Class::ResultSet> object.
59
60When calling it directly, you will not get a complete, usable row
61object until you pass or set the C<source_handle> attribute, to a
62L<DBIx::Class::ResultSource> instance that is attached to a
63L<DBIx::Class::Schema> with a valid connection.
64
65C<$attrs> is a hashref of column name, value data. It can also contain
66some other attributes such as the C<source_handle>.
7624b19f 67
33dd4e80 68Passing an object, or an arrayref of objects as a value will call
69L<DBIx::Class::Relationship::Base/set_from_related> for you. When
70passed a hashref or an arrayref of hashrefs as the value, these will
71be turned into objects via new_related, and treated as if you had
72passed objects.
73
264f1571 74For a more involved explanation, see L<DBIx::Class::ResultSet/create>.
75
7624b19f 76=cut
77
33dd4e80 78## 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().
79## This only works because DBIC doesnt yet care to check whether the new_related objects have been passed all their mandatory columns
80## When doing the later insert, we need to make sure the PKs are set.
81## using _relationship_data in new and funky ways..
82## check Relationship::CascadeActions and Relationship::Accessor for compat
83## tests!
84
370f2ba2 85sub __new_related_find_or_new_helper {
86 my ($self, $relname, $data) = @_;
87 if ($self->__their_pk_needs_us($relname, $data)) {
88 return $self->result_source
89 ->related_source($relname)
90 ->resultset
91 ->new_result($data);
92 }
93 if ($self->result_source->pk_depends_on($relname, $data)) {
94 return $self->result_source
95 ->related_source($relname)
96 ->resultset
76b8cf98 97 ->find_or_create($data);
370f2ba2 98 }
99 return $self->find_or_new_related($relname, $data);
100}
101
102sub __their_pk_needs_us { # this should maybe be in resultsource.
103 my ($self, $relname, $data) = @_;
104 my $source = $self->result_source;
105 my $reverse = $source->reverse_relationship_info($relname);
106 my $rel_source = $source->related_source($relname);
107 my $us = { $self->get_columns };
108 foreach my $key (keys %$reverse) {
109 # if their primary key depends on us, then we have to
110 # just create a result and we'll fill it out afterwards
111 return 1 if $rel_source->pk_depends_on($key, $us);
112 }
113 return 0;
114}
115
7624b19f 116sub new {
448f820f 117 my ($class, $attrs) = @_;
7624b19f 118 $class = ref $class if ref $class;
04786a4c 119
e60dc79f 120 my $new = {
121 _column_data => {},
122 };
04786a4c 123 bless $new, $class;
124
448f820f 125 if (my $handle = delete $attrs->{-source_handle}) {
126 $new->_source_handle($handle);
127 }
370f2ba2 128
129 my $source;
130 if ($source = delete $attrs->{-result_source}) {
e9fe476b 131 $new->result_source($source);
132 }
a6a280b9 133
09e1f723 134 if (my $related = delete $attrs->{-from_resultset}) {
135 @{$new->{_ignore_at_insert}={}}{@$related} = ();
136 }
137
7624b19f 138 if ($attrs) {
27f01d1f 139 $new->throw_exception("attrs must be a hashref")
140 unless ref($attrs) eq 'HASH';
61a622ee 141
142 my ($related,$inflated);
de7c7c53 143 ## Pretend all the rels are actual objects, unset below if not, for insert() to fix
144 $new->{_rel_in_storage} = 1;
8222f722 145
61a622ee 146 foreach my $key (keys %$attrs) {
147 if (ref $attrs->{$key}) {
af2d42c0 148 ## Can we extract this lot to use with update(_or .. ) ?
370f2ba2 149 confess "Can't do multi-create without result source" unless $source;
150 my $info = $source->relationship_info($key);
61a622ee 151 if ($info && $info->{attrs}{accessor}
c4a30d56 152 && $info->{attrs}{accessor} eq 'single')
61a622ee 153 {
de7c7c53 154 my $rel_obj = delete $attrs->{$key};
33dd4e80 155 if(!Scalar::Util::blessed($rel_obj)) {
370f2ba2 156 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 157 }
2bc3c81e 158
e0cdf2cb 159 if ($rel_obj->in_storage) {
160 $new->set_from_related($key, $rel_obj);
161 } else {
162 $new->{_rel_in_storage} = 0;
09e1f723 163 MULTICREATE_DEBUG and warn "MC $new uninserted $key $rel_obj\n";
e0cdf2cb 164 }
2bc3c81e 165
de7c7c53 166 $related->{$key} = $rel_obj;
61a622ee 167 next;
33dd4e80 168 } elsif ($info && $info->{attrs}{accessor}
169 && $info->{attrs}{accessor} eq 'multi'
170 && ref $attrs->{$key} eq 'ARRAY') {
2ec8e594 171 my $others = delete $attrs->{$key};
e0cdf2cb 172 my $total = @$others;
173 my @objects;
174 foreach my $idx (0 .. $#$others) {
175 my $rel_obj = $others->[$idx];
2ec8e594 176 if(!Scalar::Util::blessed($rel_obj)) {
370f2ba2 177 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 178 }
2bc3c81e 179
e0cdf2cb 180 if ($rel_obj->in_storage) {
181 $new->set_from_related($key, $rel_obj);
182 } else {
183 $new->{_rel_in_storage} = 0;
184 MULTICREATE_DEBUG and
09e1f723 185 warn "MC $new uninserted $key $rel_obj (${\($idx+1)} of $total)\n";
e0cdf2cb 186 }
370f2ba2 187 $new->set_from_related($key, $rel_obj) if $rel_obj->in_storage;
e0cdf2cb 188 push(@objects, $rel_obj);
2ec8e594 189 }
e0cdf2cb 190 $related->{$key} = \@objects;
2ec8e594 191 next;
192 } elsif ($info && $info->{attrs}{accessor}
193 && $info->{attrs}{accessor} eq 'filter')
61a622ee 194 {
33dd4e80 195 ## 'filter' should disappear and get merged in with 'single' above!
2ec8e594 196 my $rel_obj = delete $attrs->{$key};
33dd4e80 197 if(!Scalar::Util::blessed($rel_obj)) {
370f2ba2 198 $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
33dd4e80 199 }
e0cdf2cb 200 unless ($rel_obj->in_storage) {
201 $new->{_rel_in_storage} = 0;
09e1f723 202 MULTICREATE_DEBUG and warn "MC $new uninserted $key $rel_obj";
e0cdf2cb 203 }
33dd4e80 204 $inflated->{$key} = $rel_obj;
61a622ee 205 next;
2ec8e594 206 } elsif ($class->has_column($key)
207 && $class->column_info($key)->{_inflate_info}) {
61a622ee 208 $inflated->{$key} = $attrs->{$key};
209 next;
210 }
211 }
212 $new->throw_exception("No such column $key on $class")
213 unless $class->has_column($key);
214 $new->store_column($key => $attrs->{$key});
7624b19f 215 }
f90375dd 216
61a622ee 217 $new->{_relationship_data} = $related if $related;
218 $new->{_inflated_column} = $inflated if $inflated;
7624b19f 219 }
04786a4c 220
7624b19f 221 return $new;
222}
223
8091aa91 224=head2 insert
7624b19f 225
a2531bf2 226 $row->insert;
227
228=over
7624b19f 229
a2531bf2 230=item Arguments: none
231
232=item Returns: The Row object
233
234=back
235
236Inserts an object previously created by L</new> into the database if
237it isn't already in there. Returns the object itself. Requires the
238object's result source to be set, or the class to have a
239result_source_instance method. To insert an entirely new row into
240the database, use C<create> (see L<DBIx::Class::ResultSet/create>).
7624b19f 241
e91e756c 242To fetch an uninserted row object, call
243L<new|DBIx::Class::ResultSet/new> on a resultset.
244
264f1571 245This will also insert any uninserted, related objects held inside this
246one, see L<DBIx::Class::ResultSet/create> for more details.
247
7624b19f 248=cut
249
250sub insert {
251 my ($self) = @_;
252 return $self if $self->in_storage;
6aba697f 253 my $source = $self->result_source;
254 $source ||= $self->result_source($self->result_source_instance)
097d3227 255 if $self->can('result_source_instance');
aeb1bf75 256 $self->throw_exception("No result_source set on this object; can't insert")
257 unless $source;
6e399b4f 258
9c6d6d93 259 my $rollback_guard;
260
33dd4e80 261 # Check if we stored uninserted relobjs here in new()
33dd4e80 262 my %related_stuff = (%{$self->{_relationship_data} || {}},
263 %{$self->{_inflated_column} || {}});
9c6d6d93 264
ae66ef47 265 if(!$self->{_rel_in_storage}) {
8222f722 266
9c6d6d93 267 # The guard will save us if we blow out of this scope via die
1bc193ac 268 $rollback_guard = $source->storage->txn_scope_guard;
9c6d6d93 269
8222f722 270 ## Should all be in relationship_data, but we need to get rid of the
271 ## 'filter' reltype..
272 ## These are the FK rels, need their IDs for the insert.
9c6d6d93 273
274 my @pri = $self->primary_columns;
275
276 REL: foreach my $relname (keys %related_stuff) {
a8c98174 277
278 my $rel_obj = $related_stuff{$relname};
279
280 next REL unless (Scalar::Util::blessed($rel_obj)
281 && $rel_obj->isa('DBIx::Class::Row'));
282
370f2ba2 283 next REL unless $source->pk_depends_on(
284 $relname, { $rel_obj->get_columns }
285 );
9c6d6d93 286
e0cdf2cb 287 MULTICREATE_DEBUG and warn "MC $self pre-inserting $relname $rel_obj\n";
288
a8c98174 289 $rel_obj->insert();
290 $self->set_from_related($relname, $rel_obj);
291 delete $related_stuff{$relname};
33dd4e80 292 }
293 }
6e399b4f 294
09e1f723 295 MULTICREATE_DEBUG and do {
296 no warnings 'uninitialized';
297 warn "MC $self inserting (".join(', ', $self->get_columns).")\n";
298 };
ef5f6b0a 299 my $updated_cols = $source->storage->insert($source, { $self->get_columns });
645de900 300 foreach my $col (keys %$updated_cols) {
301 $self->store_column($col, $updated_cols->{$col});
302 }
ac8e89d7 303
304 ## PK::Auto
3fda409f 305 my @auto_pri = grep {
306 !defined $self->get_column($_) ||
307 ref($self->get_column($_)) eq 'SCALAR'
308 } $self->primary_columns;
309
310 if (@auto_pri) {
311 #$self->throw_exception( "More than one possible key found for auto-inc on ".ref $self )
312 # if defined $too_many;
e0cdf2cb 313 MULTICREATE_DEBUG and warn "MC $self fetching missing PKs ".join(', ', @auto_pri)."\n";
ac8e89d7 314 my $storage = $self->result_source->storage;
315 $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" )
316 unless $storage->can('last_insert_id');
3fda409f 317 my @ids = $storage->last_insert_id($self->result_source,@auto_pri);
318 $self->throw_exception( "Can't get last insert id" )
319 unless (@ids == @auto_pri);
320 $self->store_column($auto_pri[$_] => $ids[$_]) for 0 .. $#ids;
e0cdf2cb 321#use Data::Dumper; warn Dumper($self);
ac8e89d7 322 }
33dd4e80 323
e0cdf2cb 324
370f2ba2 325 $self->{_dirty_columns} = {};
326 $self->{related_resultsets} = {};
327
ae66ef47 328 if(!$self->{_rel_in_storage}) {
09e1f723 329 ## Now do the relationships that need our ID (has_many etc.)
8222f722 330 foreach my $relname (keys %related_stuff) {
9c6d6d93 331 my $rel_obj = $related_stuff{$relname};
332 my @cands;
333 if (Scalar::Util::blessed($rel_obj)
334 && $rel_obj->isa('DBIx::Class::Row')) {
335 @cands = ($rel_obj);
336 } elsif (ref $rel_obj eq 'ARRAY') {
337 @cands = @$rel_obj;
338 }
339 if (@cands) {
340 my $reverse = $source->reverse_relationship_info($relname);
341 foreach my $obj (@cands) {
342 $obj->set_from_related($_, $self) for keys %$reverse;
e912f5f0 343 my $them = { %{$obj->{_relationship_data} || {} }, $obj->get_inflated_columns };
370f2ba2 344 if ($self->__their_pk_needs_us($relname, $them)) {
09e1f723 345 if (exists $self->{_ignore_at_insert}{$relname}) {
346 MULTICREATE_DEBUG and warn "MC $self skipping post-insert on $relname";
347 } else {
348 MULTICREATE_DEBUG and warn "MC $self re-creating $relname $obj";
349 my $re = $self->find_or_create_related($relname, $them);
350 %{$obj} = %{$re};
351 MULTICREATE_DEBUG and warn "MC $self new $relname $obj";
352 }
370f2ba2 353 } else {
e0cdf2cb 354 MULTICREATE_DEBUG and warn "MC $self post-inserting $obj";
370f2ba2 355 $obj->insert();
356 }
8222f722 357 }
33dd4e80 358 }
359 }
09e1f723 360 delete $self->{_ignore_at_insert};
1bc193ac 361 $rollback_guard->commit;
33dd4e80 362 }
33dd4e80 363
7624b19f 364 $self->in_storage(1);
729b29ae 365 undef $self->{_orig_ident};
7624b19f 366 return $self;
367}
368
8091aa91 369=head2 in_storage
7624b19f 370
a2531bf2 371 $row->in_storage; # Get value
372 $row->in_storage(1); # Set value
373
374=over
375
376=item Arguments: none or 1|0
377
378=item Returns: 1|0
379
380=back
7624b19f 381
e91e756c 382Indicates whether the object exists as a row in the database or
383not. This is set to true when L<DBIx::Class::ResultSet/find>,
384L<DBIx::Class::ResultSet/create> or L<DBIx::Class::ResultSet/insert>
385are used.
386
387Creating a row object using L<DBIx::Class::ResultSet/new>, or calling
388L</delete> on one, sets it to false.
7624b19f 389
390=cut
391
392sub in_storage {
393 my ($self, $val) = @_;
394 $self->{_in_storage} = $val if @_ > 1;
395 return $self->{_in_storage};
396}
397
8091aa91 398=head2 update
7624b19f 399
a2531bf2 400 $row->update(\%columns?)
401
402=over
7624b19f 403
a2531bf2 404=item Arguments: none or a hashref
7624b19f 405
a2531bf2 406=item Returns: The Row object
407
408=back
409
410Throws an exception if the row object is not yet in the database,
411according to L</in_storage>.
412
413This method issues an SQL UPDATE query to commit any changes to the
414object to the database if required.
415
416Also takes an optional hashref of C<< column_name => value> >> pairs
417to update on the object first. Be aware that the hashref will be
418passed to C<set_inflated_columns>, which might edit it in place, so
419don't rely on it being the same after a call to C<update>. If you
420need to preserve the hashref, it is sufficient to pass a shallow copy
421to C<update>, e.g. ( { %{ $href } } )
d5d833d9 422
05d1bc9c 423If the values passed or any of the column values set on the object
424contain scalar references, eg:
425
a2531bf2 426 $row->last_modified(\'NOW()');
05d1bc9c 427 # OR
a2531bf2 428 $row->update({ last_modified => \'NOW()' });
05d1bc9c 429
430The update will pass the values verbatim into SQL. (See
431L<SQL::Abstract> docs). The values in your Row object will NOT change
432as a result of the update call, if you want the object to be updated
433with the actual values from the database, call L</discard_changes>
434after the update.
435
a2531bf2 436 $row->update()->discard_changes();
437
438To determine before calling this method, which column values have
439changed and will be updated, call L</get_dirty_columns>.
440
441To check if any columns will be updated, call L</is_changed>.
442
443To force a column to be updated, call L</make_column_dirty> before
444this method.
05d1bc9c 445
7624b19f 446=cut
447
448sub update {
449 my ($self, $upd) = @_;
701da8c4 450 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 451 my $ident_cond = $self->ident_condition;
452 $self->throw_exception("Cannot safely update a row in a PK-less table")
453 if ! keys %$ident_cond;
6e399b4f 454
bacf6f12 455 $self->set_inflated_columns($upd) if $upd;
5a9e0e60 456 my %to_update = $self->get_dirty_columns;
457 return $self unless keys %to_update;
88cb6a1d 458 my $rows = $self->result_source->storage->update(
f4afcd5d 459 $self->result_source, \%to_update,
460 $self->{_orig_ident} || $ident_cond
461 );
7624b19f 462 if ($rows == 0) {
701da8c4 463 $self->throw_exception( "Can't update ${self}: row not found" );
7624b19f 464 } elsif ($rows > 1) {
701da8c4 465 $self->throw_exception("Can't update ${self}: updated more than one row");
7624b19f 466 }
467 $self->{_dirty_columns} = {};
64acc2bc 468 $self->{related_resultsets} = {};
729b29ae 469 undef $self->{_orig_ident};
7624b19f 470 return $self;
471}
472
8091aa91 473=head2 delete
7624b19f 474
a2531bf2 475 $row->delete
476
477=over
478
479=item Arguments: none
7624b19f 480
a2531bf2 481=item Returns: The Row object
482
483=back
484
485Throws an exception if the object is not in the database according to
486L</in_storage>. Runs an SQL DELETE statement using the primary key
487values to locate the row.
488
489The object is still perfectly usable, but L</in_storage> will
ea36f4e4 490now return 0 and the object must be reinserted using L</insert>
a2531bf2 491before it can be used to L</update> the row again.
492
493If you delete an object in a class with a C<has_many> relationship, an
494attempt is made to delete all the related objects as well. To turn
495this behaviour off, pass C<< cascade_delete => 0 >> in the C<$attr>
496hashref of the relationship, see L<DBIx::Class::Relationship>. Any
497database-level cascade or restrict will take precedence over a
498DBIx-Class-based cascading delete.
499
b1d16ffd 500If you delete an object within a txn_do() (see L<DBIx::Class::Storage/txn_do>)
501and the transaction subsequently fails, the row object will remain marked as
502not being in storage. If you know for a fact that the object is still in
503storage (i.e. by inspecting the cause of the transaction's failure), you can
504use C<< $obj->in_storage(1) >> to restore consistency between the object and
505the database. This would allow a subsequent C<< $obj->delete >> to work
506as expected.
507
a2531bf2 508See also L<DBIx::Class::ResultSet/delete>.
7624b19f 509
510=cut
511
512sub delete {
513 my $self = shift;
514 if (ref $self) {
701da8c4 515 $self->throw_exception( "Not in database" ) unless $self->in_storage;
728e60a3 516 my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
4b12b3c2 517 $self->throw_exception("Cannot safely delete a row in a PK-less table")
518 if ! keys %$ident_cond;
e0f56292 519 foreach my $column (keys %$ident_cond) {
75d07914 520 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
521 unless exists $self->{_column_data}{$column};
e0f56292 522 }
88cb6a1d 523 $self->result_source->storage->delete(
7af8b477 524 $self->result_source, $ident_cond);
7624b19f 525 $self->in_storage(undef);
7624b19f 526 } else {
701da8c4 527 $self->throw_exception("Can't do class delete without a ResultSource instance")
097d3227 528 unless $self->can('result_source_instance');
aeb1bf75 529 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
530 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
097d3227 531 $self->result_source_instance->resultset->search(@_)->delete;
7624b19f 532 }
533 return $self;
534}
535
8091aa91 536=head2 get_column
7624b19f 537
a2531bf2 538 my $val = $row->get_column($col);
539
540=over
541
542=item Arguments: $columnname
543
544=item Returns: The value of the column
545
546=back
547
548Throws an exception if the column name given doesn't exist according
549to L</has_column>.
7624b19f 550
e91e756c 551Returns a raw column value from the row object, if it has already
552been fetched from the database or set by an accessor.
553
554If an L<inflated value|DBIx::Class::InflateColumn> has been set, it
555will be deflated and returned.
7624b19f 556
ea36f4e4 557Note that if you used the C<columns> or the C<select/as>
558L<search attributes|DBIx::Class::ResultSet/ATTRIBUTES> on the resultset from
559which C<$row> was derived, and B<did not include> C<$columnname> in the list,
560this method will return C<undef> even if the database contains some value.
561
a2531bf2 562To retrieve all loaded column values as a hash, use L</get_columns>.
563
7624b19f 564=cut
565
566sub get_column {
567 my ($self, $column) = @_;
701da8c4 568 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
aeb1bf75 569 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
61a622ee 570 if (exists $self->{_inflated_column}{$column}) {
571 return $self->store_column($column,
572 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
573 }
701da8c4 574 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
7624b19f 575 return undef;
576}
577
9b83fccd 578=head2 has_column_loaded
579
a2531bf2 580 if ( $row->has_column_loaded($col) ) {
9b83fccd 581 print "$col has been loaded from db";
582 }
583
a2531bf2 584=over
585
586=item Arguments: $columnname
587
588=item Returns: 0|1
589
590=back
591
9b83fccd 592Returns a true value if the column value has been loaded from the
593database (or set locally).
594
595=cut
596
def81720 597sub has_column_loaded {
598 my ($self, $column) = @_;
599 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
61a622ee 600 return 1 if exists $self->{_inflated_column}{$column};
aeb1bf75 601 return exists $self->{_column_data}{$column};
def81720 602}
603
8091aa91 604=head2 get_columns
076a6864 605
a2531bf2 606 my %data = $row->get_columns;
607
608=over
609
610=item Arguments: none
076a6864 611
a2531bf2 612=item Returns: A hash of columnname, value pairs.
613
614=back
615
616Returns all loaded column data as a hash, containing raw values. To
617get just one value for a particular column, use L</get_column>.
076a6864 618
619=cut
620
621sub get_columns {
622 my $self = shift;
61a622ee 623 if (exists $self->{_inflated_column}) {
624 foreach my $col (keys %{$self->{_inflated_column}}) {
625 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
c4a30d56 626 unless exists $self->{_column_data}{$col};
61a622ee 627 }
628 }
cb5f2eea 629 return %{$self->{_column_data}};
d7156e50 630}
631
632=head2 get_dirty_columns
633
a2531bf2 634 my %data = $row->get_dirty_columns;
635
636=over
637
638=item Arguments: none
d7156e50 639
a2531bf2 640=item Returns: A hash of column, value pairs
641
642=back
643
644Only returns the column, value pairs for those columns that have been
645changed on this object since the last L</update> or L</insert> call.
646
647See L</get_columns> to fetch all column/value pairs.
d7156e50 648
649=cut
650
651sub get_dirty_columns {
652 my $self = shift;
653 return map { $_ => $self->{_column_data}{$_} }
654 keys %{$self->{_dirty_columns}};
076a6864 655}
656
6dbea98e 657=head2 make_column_dirty
658
a2531bf2 659 $row->make_column_dirty($col)
660
661=over
662
663=item Arguments: $columnname
664
665=item Returns: undefined
666
667=back
668
669Throws an exception if the column does not exist.
670
671Marks a column as having been changed regardless of whether it has
672really changed.
6dbea98e 673
674=cut
675sub make_column_dirty {
676 my ($self, $column) = @_;
677
678 $self->throw_exception( "No such column '${column}'" )
679 unless exists $self->{_column_data}{$column} || $self->has_column($column);
680 $self->{_dirty_columns}{$column} = 1;
681}
682
ba4a6453 683=head2 get_inflated_columns
684
e91e756c 685 my %inflated_data = $obj->get_inflated_columns;
ba4a6453 686
a2531bf2 687=over
688
689=item Arguments: none
690
691=item Returns: A hash of column, object|value pairs
692
693=back
694
695Returns a hash of all column keys and associated values. Values for any
696columns set to use inflation will be inflated and returns as objects.
697
698See L</get_columns> to get the uninflated values.
699
700See L<DBIx::Class::InflateColumn> for how to setup inflation.
ba4a6453 701
702=cut
703
704sub get_inflated_columns {
705 my $self = shift;
706 return map {
707 my $accessor = $self->column_info($_)->{'accessor'} || $_;
708 ($_ => $self->$accessor);
709 } $self->columns;
710}
711
8091aa91 712=head2 set_column
7624b19f 713
a2531bf2 714 $row->set_column($col => $val);
715
716=over
717
718=item Arguments: $columnname, $value
719
720=item Returns: $value
721
722=back
7624b19f 723
e91e756c 724Sets a raw column value. If the new value is different from the old one,
a2531bf2 725the column is marked as dirty for when you next call L</update>.
7624b19f 726
ea36f4e4 727If passed an object or reference as a value, this method will happily
728attempt to store it, and a later L</insert> or L</update> will try and
a2531bf2 729stringify/numify as appropriate. To set an object to be deflated
730instead, see L</set_inflated_columns>.
e91e756c 731
7624b19f 732=cut
733
734sub set_column {
1d0057bd 735 my ($self, $column, $new_value) = @_;
736
729b29ae 737 $self->{_orig_ident} ||= $self->ident_condition;
1d0057bd 738 my $old_value = $self->get_column($column);
739
740 $self->store_column($column, $new_value);
87772e46 741 $self->{_dirty_columns}{$column} = 1
1d0057bd 742 if (defined $old_value xor defined $new_value) || (defined $old_value && $old_value ne $new_value);
e60dc79f 743
744 # XXX clear out the relation cache for this column
745 delete $self->{related_resultsets}{$column};
746
1d0057bd 747 return $new_value;
7624b19f 748}
749
8091aa91 750=head2 set_columns
076a6864 751
a2531bf2 752 $row->set_columns({ $col => $val, ... });
753
754=over
076a6864 755
a2531bf2 756=item Arguments: \%columndata
757
758=item Returns: The Row object
759
760=back
761
762Sets multiple column, raw value pairs at once.
763
764Works as L</set_column>.
076a6864 765
766=cut
767
768sub set_columns {
769 my ($self,$data) = @_;
a2ca474b 770 foreach my $col (keys %$data) {
771 $self->set_column($col,$data->{$col});
076a6864 772 }
c01ab172 773 return $self;
076a6864 774}
775
bacf6f12 776=head2 set_inflated_columns
777
a2531bf2 778 $row->set_inflated_columns({ $col => $val, $relname => $obj, ... });
779
780=over
781
782=item Arguments: \%columndata
783
784=item Returns: The Row object
785
786=back
787
788Sets more than one column value at once. Any inflated values are
789deflated and the raw values stored.
bacf6f12 790
a2531bf2 791Any related values passed as Row objects, using the relation name as a
792key, are reduced to the appropriate foreign key values and stored. If
793instead of related row objects, a hashref of column, value data is
794passed, will create the related object first then store.
795
796Will even accept arrayrefs of data as a value to a
797L<DBIx::Class::Relationship/has_many> key, and create the related
798objects if necessary.
799
800Be aware that the input hashref might be edited in place, so dont rely
801on it being the same after a call to C<set_inflated_columns>. If you
802need to preserve the hashref, it is sufficient to pass a shallow copy
803to C<set_inflated_columns>, e.g. ( { %{ $href } } )
804
805See also L<DBIx::Class::Relationship::Base/set_from_related>.
bacf6f12 806
807=cut
808
809sub set_inflated_columns {
810 my ( $self, $upd ) = @_;
811 foreach my $key (keys %$upd) {
812 if (ref $upd->{$key}) {
813 my $info = $self->relationship_info($key);
814 if ($info && $info->{attrs}{accessor}
815 && $info->{attrs}{accessor} eq 'single')
816 {
817 my $rel = delete $upd->{$key};
818 $self->set_from_related($key => $rel);
a7be8807 819 $self->{_relationship_data}{$key} = $rel;
bacf6f12 820 } elsif ($info && $info->{attrs}{accessor}
a7be8807 821 && $info->{attrs}{accessor} eq 'multi') {
822 $self->throw_exception(
823 "Recursive update is not supported over relationships of type multi ($key)"
824 );
bacf6f12 825 }
826 elsif ($self->has_column($key)
827 && exists $self->column_info($key)->{_inflate_info})
828 {
a7be8807 829 $self->set_inflated_column($key, delete $upd->{$key});
bacf6f12 830 }
831 }
832 }
833 $self->set_columns($upd);
834}
835
8091aa91 836=head2 copy
076a6864 837
838 my $copy = $orig->copy({ change => $to, ... });
839
a2531bf2 840=over
841
842=item Arguments: \%replacementdata
843
844=item Returns: The Row object copy
845
846=back
847
848Inserts a new row into the database, as a copy of the original
849object. If a hashref of replacement data is supplied, these will take
850precedence over data in the original.
851
852If the row has related objects in a
853L<DBIx::Class::Relationship/has_many> then those objects may be copied
854too depending on the L<cascade_copy|DBIx::Class::Relationship>
855relationship attribute.
076a6864 856
857=cut
858
c01ab172 859sub copy {
860 my ($self, $changes) = @_;
333cce60 861 $changes ||= {};
fde6e28e 862 my $col_data = { %{$self->{_column_data}} };
863 foreach my $col (keys %$col_data) {
864 delete $col_data->{$col}
865 if $self->result_source->column_info($col)->{is_auto_increment};
866 }
04786a4c 867
868 my $new = { _column_data => $col_data };
869 bless $new, ref $self;
870
83419ec6 871 $new->result_source($self->result_source);
bacf6f12 872 $new->set_inflated_columns($changes);
333cce60 873 $new->insert;
35688220 874
875 # Its possible we'll have 2 relations to the same Source. We need to make
876 # sure we don't try to insert the same row twice esle we'll violate unique
877 # constraints
878 my $rels_copied = {};
879
333cce60 880 foreach my $rel ($self->result_source->relationships) {
881 my $rel_info = $self->result_source->relationship_info($rel);
35688220 882
883 next unless $rel_info->{attrs}{cascade_copy};
884
885 my $resolved = $self->result_source->resolve_condition(
886 $rel_info->{cond}, $rel, $new
887 );
888
889 my $copied = $rels_copied->{ $rel_info->{source} } ||= {};
890 foreach my $related ($self->search_related($rel)) {
891 my $id_str = join("\0", $related->id);
892 next if $copied->{$id_str};
893 $copied->{$id_str} = 1;
894 my $rel_copy = $related->copy($resolved);
333cce60 895 }
35688220 896
333cce60 897 }
2c4c67b6 898 return $new;
c01ab172 899}
900
8091aa91 901=head2 store_column
7624b19f 902
a2531bf2 903 $row->store_column($col => $val);
7624b19f 904
a2531bf2 905=over
906
907=item Arguments: $columnname, $value
908
ea36f4e4 909=item Returns: The value sent to storage
a2531bf2 910
911=back
912
913Set a raw value for a column without marking it as changed. This
914method is used internally by L</set_column> which you should probably
915be using.
916
917This is the lowest level at which data is set on a row object,
918extend this method to catch all data setting methods.
7624b19f 919
920=cut
921
922sub store_column {
923 my ($self, $column, $value) = @_;
75d07914 924 $self->throw_exception( "No such column '${column}'" )
d7156e50 925 unless exists $self->{_column_data}{$column} || $self->has_column($column);
75d07914 926 $self->throw_exception( "set_column called for ${column} without value" )
7624b19f 927 if @_ < 3;
928 return $self->{_column_data}{$column} = $value;
929}
930
b52e9bf8 931=head2 inflate_result
932
c01ab172 933 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 934
a2531bf2 935=over
936
937=item Arguments: $result_source, \%columndata, \%prefetcheddata
938
939=item Returns: A Row object
940
941=back
942
943All L<DBIx::Class::ResultSet> methods that retrieve data from the
944database and turn it into row objects call this method.
945
946Extend this method in your Result classes to hook into this process,
947for example to rebless the result into a different class.
948
949Reblessing can also be done more easily by setting C<result_class> in
950your Result class. See L<DBIx::Class::ResultSource/result_class>.
b52e9bf8 951
952=cut
953
954sub inflate_result {
c01ab172 955 my ($class, $source, $me, $prefetch) = @_;
aec3eff1 956
957 my ($source_handle) = $source;
958
959 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
960 $source = $source_handle->resolve
961 } else {
962 $source_handle = $source->handle
963 }
964
04786a4c 965 my $new = {
aec3eff1 966 _source_handle => $source_handle,
04786a4c 967 _column_data => $me,
968 _in_storage => 1
969 };
970 bless $new, (ref $class || $class);
971
7fb16f1a 972 my $schema;
64acc2bc 973 foreach my $pre (keys %{$prefetch||{}}) {
974 my $pre_val = $prefetch->{$pre};
f9cc31dd 975 my $pre_source = $source->related_source($pre);
a86b1efe 976 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
977 unless $pre_source;
0f66a01b 978 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
a86b1efe 979 my @pre_objects;
980 foreach my $pre_rec (@$pre_val) {
75d07914 981 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
5a5bec6c 982 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
a86b1efe 983 next;
984 }
985 push(@pre_objects, $pre_source->result_class->inflate_result(
986 $pre_source, @{$pre_rec}));
987 }
988 $new->related_resultset($pre)->set_cache(\@pre_objects);
62e87ea8 989 } elsif (defined $pre_val->[0]) {
a86b1efe 990 my $fetched;
75d07914 991 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
a86b1efe 992 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
993 {
994 $fetched = $pre_source->result_class->inflate_result(
75d07914 995 $pre_source, @{$pre_val});
a86b1efe 996 }
9809a6df 997 $new->related_resultset($pre)->set_cache([ $fetched ]);
a86b1efe 998 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
999 $class->throw_exception("No accessor for prefetched $pre")
1000 unless defined $accessor;
1001 if ($accessor eq 'single') {
1002 $new->{_relationship_data}{$pre} = $fetched;
1003 } elsif ($accessor eq 'filter') {
1004 $new->{_inflated_column}{$pre} = $fetched;
1005 } else {
1006 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
1007 }
b52e9bf8 1008 }
1009 }
7624b19f 1010 return $new;
1011}
1012
9b465d00 1013=head2 update_or_insert
7624b19f 1014
a2531bf2 1015 $row->update_or_insert
1016
1017=over
7624b19f 1018
a2531bf2 1019=item Arguments: none
1020
1021=item Returns: Result of update or insert operation
1022
1023=back
1024
1025L</Update>s the object if it's already in the database, according to
1026L</in_storage>, else L</insert>s it.
7624b19f 1027
9b83fccd 1028=head2 insert_or_update
1029
1030 $obj->insert_or_update
1031
1032Alias for L</update_or_insert>
1033
7624b19f 1034=cut
1035
370f2ba2 1036sub insert_or_update { shift->update_or_insert(@_) }
1037
9b465d00 1038sub update_or_insert {
7624b19f 1039 my $self = shift;
1040 return ($self->in_storage ? $self->update : $self->insert);
1041}
1042
8091aa91 1043=head2 is_changed
7624b19f 1044
a2531bf2 1045 my @changed_col_names = $row->is_changed();
1046 if ($row->is_changed()) { ... }
1047
1048=over
7624b19f 1049
a2531bf2 1050=item Arguments: none
1051
1052=item Returns: 0|1 or @columnnames
1053
1054=back
1055
1056In list context returns a list of columns with uncommited changes, or
9b83fccd 1057in scalar context returns a true value if there are uncommitted
1058changes.
1059
7624b19f 1060=cut
1061
1062sub is_changed {
1063 return keys %{shift->{_dirty_columns} || {}};
1064}
228dbcb4 1065
1066=head2 is_column_changed
1067
a2531bf2 1068 if ($row->is_column_changed('col')) { ... }
1069
1070=over
1071
1072=item Arguments: $columname
1073
1074=item Returns: 0|1
1075
1076=back
228dbcb4 1077
9b83fccd 1078Returns a true value if the column has uncommitted changes.
1079
228dbcb4 1080=cut
1081
1082sub is_column_changed {
1083 my( $self, $col ) = @_;
1084 return exists $self->{_dirty_columns}->{$col};
1085}
7624b19f 1086
097d3227 1087=head2 result_source
1088
a2531bf2 1089 my $resultsource = $row->result_source;
1090
1091=over
1092
1093=item Arguments: none
097d3227 1094
a2531bf2 1095=item Returns: a ResultSource instance
1096
1097=back
1098
1099Accessor to the L<DBIx::Class::ResultSource> this object was created from.
87c4e602 1100
aec3eff1 1101=cut
1102
1103sub result_source {
1104 my $self = shift;
1105
1106 if (@_) {
1107 $self->_source_handle($_[0]->handle);
1108 } else {
1109 $self->_source_handle->resolve;
1110 }
1111}
1112
9b83fccd 1113=head2 register_column
27f01d1f 1114
9b83fccd 1115 $column_info = { .... };
1116 $class->register_column($column_name, $column_info);
27f01d1f 1117
a2531bf2 1118=over
1119
1120=item Arguments: $columnname, \%columninfo
1121
1122=item Returns: undefined
1123
1124=back
1125
9b83fccd 1126Registers a column on the class. If the column_info has an 'accessor'
1127key, creates an accessor named after the value if defined; if there is
1128no such key, creates an accessor with the same name as the column
1f23a877 1129
9b83fccd 1130The column_info attributes are described in
1131L<DBIx::Class::ResultSource/add_columns>
1f23a877 1132
097d3227 1133=cut
1134
1f23a877 1135sub register_column {
1136 my ($class, $col, $info) = @_;
91b0fbd7 1137 my $acc = $col;
1138 if (exists $info->{accessor}) {
1139 return unless defined $info->{accessor};
1140 $acc = [ $info->{accessor}, $col ];
1141 }
1142 $class->mk_group_accessors('column' => $acc);
1f23a877 1143}
1144
a2531bf2 1145=head2 get_from_storage
1146
1147 my $copy = $row->get_from_storage($attrs)
1148
1149=over
b9b4e52f 1150
a2531bf2 1151=item Arguments: \%attrs
b9b4e52f 1152
a2531bf2 1153=item Returns: A Row object
1154
1155=back
1156
1157Fetches a fresh copy of the Row object from the database and returns it.
1158
1159If passed the \%attrs argument, will first apply these attributes to
1160the resultset used to find the row.
1161
1162This copy can then be used to compare to an existing row object, to
1163determine if any changes have been made in the database since it was
1164created.
1165
1166To just update your Row object with any latest changes from the
1167database, use L</discard_changes> instead.
1168
1169The \%attrs argument should be compatible with
1170L<DBIx::Class::ResultSet/ATTRIBUTES>.
7e38d850 1171
b9b4e52f 1172=cut
1173
a737512c 1174sub get_from_storage {
b9b4e52f 1175 my $self = shift @_;
7e38d850 1176 my $attrs = shift @_;
7e38d850 1177 my $resultset = $self->result_source->resultset;
1178
1179 if(defined $attrs) {
1180 $resultset = $resultset->search(undef, $attrs);
1181 }
1182
728e60a3 1183 return $resultset->find($self->{_orig_ident} || $self->ident_condition);
b9b4e52f 1184}
701da8c4 1185
5160b401 1186=head2 throw_exception
701da8c4 1187
a2531bf2 1188See L<DBIx::Class::Schema/throw_exception>.
701da8c4 1189
1190=cut
1191
1192sub throw_exception {
1193 my $self=shift;
66cab05c 1194 if (ref $self && ref $self->result_source && $self->result_source->schema) {
701da8c4 1195 $self->result_source->schema->throw_exception(@_);
1196 } else {
1197 croak(@_);
1198 }
1199}
1200
33cf6616 1201=head2 id
1202
a2531bf2 1203 my @pk = $row->id;
1204
1205=over
1206
1207=item Arguments: none
1208
1209=item Returns: A list of primary key values
1210
1211=back
1212
33cf6616 1213Returns the primary key(s) for a row. Can't be called as a class method.
f7043881 1214Actually implemented in L<DBIx::Class::PK>
33cf6616 1215
1216=head2 discard_changes
1217
a2531bf2 1218 $row->discard_changes
1219
1220=over
1221
1222=item Arguments: none
1223
1224=item Returns: nothing (updates object in-place)
1225
1226=back
1227
1228Retrieves and sets the row object data from the database, losing any
1229local changes made.
33cf6616 1230
1231This method can also be used to refresh from storage, retrieving any
1232changes made since the row was last read from storage. Actually
f7043881 1233implemented in L<DBIx::Class::PK>
33cf6616 1234
1235=cut
1236
7624b19f 12371;
1238
7624b19f 1239=head1 AUTHORS
1240
daec44b8 1241Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 1242
1243=head1 LICENSE
1244
1245You may distribute this code under the same terms as Perl itself.
1246
1247=cut