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