1 package DBIx::Class::Row;
6 use base qw/DBIx::Class/;
7 use Carp::Clan qw/^DBIx::Class/;
11 __PACKAGE__->mk_group_accessors('simple' => qw/_source_handle/);
15 DBIx::Class::Row - Basic row methods
21 This class is responsible for defining and doing basic operations on rows
22 derived from L<DBIx::Class::ResultSource> objects.
28 my $obj = My::Class->new($attrs);
30 Creates a new row object from column => value mappings passed as a hash ref
32 Passing an object, or an arrayref of objects as a value will call
33 L<DBIx::Class::Relationship::Base/set_from_related> for you. When
34 passed a hashref or an arrayref of hashrefs as the value, these will
35 be turned into objects via new_related, and treated as if you had
38 For a more involved explanation, see L<DBIx::Class::ResultSet/create>.
42 ## It needs to store the new objects somewhere, and call insert on that list later when insert is called on this object. We may need an accessor for these so the user can retrieve them, if just doing ->new().
43 ## This only works because DBIC doesnt yet care to check whether the new_related objects have been passed all their mandatory columns
44 ## When doing the later insert, we need to make sure the PKs are set.
45 ## using _relationship_data in new and funky ways..
46 ## check Relationship::CascadeActions and Relationship::Accessor for compat
50 my ($class, $attrs) = @_;
51 $class = ref $class if ref $class;
58 if (my $handle = delete $attrs->{-source_handle}) {
59 $new->_source_handle($handle);
61 if (my $source = delete $attrs->{-result_source}) {
62 $new->result_source($source);
66 $new->throw_exception("attrs must be a hashref")
67 unless ref($attrs) eq 'HASH';
69 my ($related,$inflated);
70 ## Pretend all the rels are actual objects, unset below if not, for insert() to fix
71 $new->{_rel_in_storage} = 1;
73 foreach my $key (keys %$attrs) {
74 if (ref $attrs->{$key}) {
75 ## Can we extract this lot to use with update(_or .. ) ?
76 my $info = $class->relationship_info($key);
77 if ($info && $info->{attrs}{accessor}
78 && $info->{attrs}{accessor} eq 'single')
80 my $rel_obj = delete $attrs->{$key};
81 if(!Scalar::Util::blessed($rel_obj)) {
82 $rel_obj = $new->find_or_new_related($key, $rel_obj);
85 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
87 $new->set_from_related($key, $rel_obj);
88 $related->{$key} = $rel_obj;
90 } elsif ($info && $info->{attrs}{accessor}
91 && $info->{attrs}{accessor} eq 'multi'
92 && ref $attrs->{$key} eq 'ARRAY') {
93 my $others = delete $attrs->{$key};
94 foreach my $rel_obj (@$others) {
95 if(!Scalar::Util::blessed($rel_obj)) {
96 $rel_obj = $new->new_related($key, $rel_obj);
97 $new->{_rel_in_storage} = 0;
100 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
102 $related->{$key} = $others;
104 } elsif ($info && $info->{attrs}{accessor}
105 && $info->{attrs}{accessor} eq 'filter')
107 ## 'filter' should disappear and get merged in with 'single' above!
108 my $rel_obj = delete $attrs->{$key};
109 if(!Scalar::Util::blessed($rel_obj)) {
110 $rel_obj = $new->find_or_new_related($key, $rel_obj);
111 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
113 $inflated->{$key} = $rel_obj;
115 } elsif ($class->has_column($key)
116 && $class->column_info($key)->{_inflate_info}) {
117 $inflated->{$key} = $attrs->{$key};
121 $new->throw_exception("No such column $key on $class")
122 unless $class->has_column($key);
123 $new->store_column($key => $attrs->{$key});
126 $new->{_relationship_data} = $related if $related;
127 $new->{_inflated_column} = $inflated if $inflated;
137 Inserts an object into the database if it isn't already in
138 there. Returns the object itself. Requires the object's result source to
139 be set, or the class to have a result_source_instance method. To insert
140 an entirely new object into the database, use C<create> (see
141 L<DBIx::Class::ResultSet/create>).
143 This will also insert any uninserted, related objects held inside this
144 one, see L<DBIx::Class::ResultSet/create> for more details.
150 return $self if $self->in_storage;
151 my $source = $self->result_source;
152 $source ||= $self->result_source($self->result_source_instance)
153 if $self->can('result_source_instance');
154 $self->throw_exception("No result_source set on this object; can't insert")
159 # Check if we stored uninserted relobjs here in new()
160 my %related_stuff = (%{$self->{_relationship_data} || {}},
161 %{$self->{_inflated_column} || {}});
163 if(!$self->{_rel_in_storage}) {
165 # The guard will save us if we blow out of this scope via die
166 $rollback_guard = $source->storage->txn_scope_guard;
168 ## Should all be in relationship_data, but we need to get rid of the
169 ## 'filter' reltype..
170 ## These are the FK rels, need their IDs for the insert.
172 my @pri = $self->primary_columns;
174 REL: foreach my $relname (keys %related_stuff) {
176 my $rel_obj = $related_stuff{$relname};
178 next REL unless (Scalar::Util::blessed($rel_obj)
179 && $rel_obj->isa('DBIx::Class::Row'));
181 my $cond = $source->relationship_info($relname)->{cond};
183 next REL unless ref($cond) eq 'HASH';
185 # map { foreign.foo => 'self.bar' } to { bar => 'foo' }
187 my $keyhash = { map { my $x = $_; $x =~ s/.*\.//; $x; } reverse %$cond };
189 # assume anything that references our PK probably is dependent on us
190 # rather than vice versa, unless the far side is (a) defined or (b)
193 foreach my $p (@pri) {
194 if (exists $keyhash->{$p}) {
195 unless (defined($rel_obj->get_column($keyhash->{$p}))
196 || $rel_obj->column_info($keyhash->{$p})
197 ->{is_auto_increment}) {
204 $self->set_from_related($relname, $rel_obj);
205 delete $related_stuff{$relname};
209 $source->storage->insert($source, { $self->get_columns });
212 my @auto_pri = grep {
213 !defined $self->get_column($_) ||
214 ref($self->get_column($_)) eq 'SCALAR'
215 } $self->primary_columns;
218 #$self->throw_exception( "More than one possible key found for auto-inc on ".ref $self )
219 # if defined $too_many;
221 my $storage = $self->result_source->storage;
222 $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" )
223 unless $storage->can('last_insert_id');
224 my @ids = $storage->last_insert_id($self->result_source,@auto_pri);
225 $self->throw_exception( "Can't get last insert id" )
226 unless (@ids == @auto_pri);
227 $self->store_column($auto_pri[$_] => $ids[$_]) for 0 .. $#ids;
230 if(!$self->{_rel_in_storage}) {
231 ## Now do the has_many rels, that need $selfs ID.
232 foreach my $relname (keys %related_stuff) {
233 my $rel_obj = $related_stuff{$relname};
235 if (Scalar::Util::blessed($rel_obj)
236 && $rel_obj->isa('DBIx::Class::Row')) {
238 } elsif (ref $rel_obj eq 'ARRAY') {
242 my $reverse = $source->reverse_relationship_info($relname);
243 foreach my $obj (@cands) {
244 $obj->set_from_related($_, $self) for keys %$reverse;
245 $obj->insert() unless ($obj->in_storage || $obj->result_source->resultset->search({$obj->get_columns})->count);
249 $rollback_guard->commit;
252 $self->in_storage(1);
253 $self->{_dirty_columns} = {};
254 $self->{related_resultsets} = {};
255 undef $self->{_orig_ident};
261 $obj->in_storage; # Get value
262 $obj->in_storage(1); # Set value
264 Indicates whether the object exists as a row in the database or not
269 my ($self, $val) = @_;
270 $self->{_in_storage} = $val if @_ > 1;
271 return $self->{_in_storage};
276 $obj->update \%columns?;
278 Must be run on an object that is already in the database; issues an SQL
279 UPDATE query to commit any changes to the object to the database if
282 Also takes an options hashref of C<< column_name => value> pairs >> to update
283 first. But be aware that the hashref will be passed to
284 C<set_inflated_columns>, which might edit it in place, so dont rely on it being
285 the same after a call to C<update>. If you need to preserve the hashref, it is
286 sufficient to pass a shallow copy to C<update>, e.g. ( { %{ $href } } )
291 my ($self, $upd) = @_;
292 $self->throw_exception( "Not in database" ) unless $self->in_storage;
293 my $ident_cond = $self->ident_condition;
294 $self->throw_exception("Cannot safely update a row in a PK-less table")
295 if ! keys %$ident_cond;
297 $self->set_inflated_columns($upd) if $upd;
298 my %to_update = $self->get_dirty_columns;
299 return $self unless keys %to_update;
300 my $rows = $self->result_source->storage->update(
301 $self->result_source, \%to_update,
302 $self->{_orig_ident} || $ident_cond
305 $self->throw_exception( "Can't update ${self}: row not found" );
306 } elsif ($rows > 1) {
307 $self->throw_exception("Can't update ${self}: updated more than one row");
309 $self->{_dirty_columns} = {};
310 $self->{related_resultsets} = {};
311 undef $self->{_orig_ident};
319 Deletes the object from the database. The object is still perfectly
320 usable, but C<< ->in_storage() >> will now return 0 and the object must
321 reinserted using C<< ->insert() >> before C<< ->update() >> can be used
322 on it. If you delete an object in a class with a C<has_many>
323 relationship, all the related objects will be deleted as well. To turn
324 this behavior off, pass C<< cascade_delete => 0 >> in the C<$attr>
325 hashref. Any database-level cascade or restrict will take precedence
326 over a DBIx-Class-based cascading delete. See also L<DBIx::Class::ResultSet/delete>.
333 $self->throw_exception( "Not in database" ) unless $self->in_storage;
334 my $ident_cond = $self->ident_condition;
335 $self->throw_exception("Cannot safely delete a row in a PK-less table")
336 if ! keys %$ident_cond;
337 foreach my $column (keys %$ident_cond) {
338 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
339 unless exists $self->{_column_data}{$column};
341 $self->result_source->storage->delete(
342 $self->result_source, $ident_cond);
343 $self->in_storage(undef);
345 $self->throw_exception("Can't do class delete without a ResultSource instance")
346 unless $self->can('result_source_instance');
347 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
348 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
349 $self->result_source_instance->resultset->search(@_)->delete;
356 my $val = $obj->get_column($col);
358 Gets a column value from a row object. Does not do any queries; the column
359 must have already been fetched from the database and stored in the object. If
360 there is an inflated value stored that has not yet been deflated, it is deflated
361 when the method is invoked.
366 my ($self, $column) = @_;
367 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
368 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
369 if (exists $self->{_inflated_column}{$column}) {
370 return $self->store_column($column,
371 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
373 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
377 =head2 has_column_loaded
379 if ( $obj->has_column_loaded($col) ) {
380 print "$col has been loaded from db";
383 Returns a true value if the column value has been loaded from the
384 database (or set locally).
388 sub has_column_loaded {
389 my ($self, $column) = @_;
390 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
391 return 1 if exists $self->{_inflated_column}{$column};
392 return exists $self->{_column_data}{$column};
397 my %data = $obj->get_columns;
399 Does C<get_column>, for all column values at once.
405 if (exists $self->{_inflated_column}) {
406 foreach my $col (keys %{$self->{_inflated_column}}) {
407 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
408 unless exists $self->{_column_data}{$col};
411 return %{$self->{_column_data}};
414 =head2 get_dirty_columns
416 my %data = $obj->get_dirty_columns;
418 Identical to get_columns but only returns those that have been changed.
422 sub get_dirty_columns {
424 return map { $_ => $self->{_column_data}{$_} }
425 keys %{$self->{_dirty_columns}};
428 =head2 get_inflated_columns
430 my $inflated_data = $obj->get_inflated_columns;
432 Similar to get_columns but objects are returned for inflated columns instead of their raw non-inflated values.
436 sub get_inflated_columns {
439 my $accessor = $self->column_info($_)->{'accessor'} || $_;
440 ($_ => $self->$accessor);
446 $obj->set_column($col => $val);
448 Sets a column value. If the new value is different from the old one,
449 the column is marked as dirty for when you next call $obj->update.
456 $self->{_orig_ident} ||= $self->ident_condition;
457 my $old = $self->get_column($column);
458 my $ret = $self->store_column(@_);
459 $self->{_dirty_columns}{$column} = 1
460 if (defined $old xor defined $ret) || (defined $old && $old ne $ret);
462 # XXX clear out the relation cache for this column
463 delete $self->{related_resultsets}{$column};
470 my $copy = $orig->set_columns({ $col => $val, ... });
472 Sets more than one column value at once.
477 my ($self,$data) = @_;
478 foreach my $col (keys %$data) {
479 $self->set_column($col,$data->{$col});
484 =head2 set_inflated_columns
486 my $copy = $orig->set_inflated_columns({ $col => $val, $rel => $obj, ... });
488 Sets more than one column value at once, taking care to respect inflations and
489 relationships if relevant. Be aware that this hashref might be edited in place,
490 so dont rely on it being the same after a call to C<set_inflated_columns>. If
491 you need to preserve the hashref, it is sufficient to pass a shallow copy to
492 C<set_inflated_columns>, e.g. ( { %{ $href } } )
496 sub set_inflated_columns {
497 my ( $self, $upd ) = @_;
498 foreach my $key (keys %$upd) {
499 if (ref $upd->{$key}) {
500 my $info = $self->relationship_info($key);
501 if ($info && $info->{attrs}{accessor}
502 && $info->{attrs}{accessor} eq 'single')
504 my $rel = delete $upd->{$key};
505 $self->set_from_related($key => $rel);
506 $self->{_relationship_data}{$key} = $rel;
507 } elsif ($info && $info->{attrs}{accessor}
508 && $info->{attrs}{accessor} eq 'multi'
509 && ref $upd->{$key} eq 'ARRAY') {
510 my $others = delete $upd->{$key};
511 foreach my $rel_obj (@$others) {
512 if(!Scalar::Util::blessed($rel_obj)) {
513 $rel_obj = $self->create_related($key, $rel_obj);
516 $self->{_relationship_data}{$key} = $others;
517 # $related->{$key} = $others;
520 elsif ($self->has_column($key)
521 && exists $self->column_info($key)->{_inflate_info})
523 $self->set_inflated_column($key, delete $upd->{$key});
527 $self->set_columns($upd);
532 my $copy = $orig->copy({ change => $to, ... });
534 Inserts a new row with the specified changes.
539 my ($self, $changes) = @_;
541 my $col_data = { %{$self->{_column_data}} };
542 foreach my $col (keys %$col_data) {
543 delete $col_data->{$col}
544 if $self->result_source->column_info($col)->{is_auto_increment};
547 my $new = { _column_data => $col_data };
548 bless $new, ref $self;
550 $new->result_source($self->result_source);
551 $new->set_inflated_columns($changes);
554 # Its possible we'll have 2 relations to the same Source. We need to make
555 # sure we don't try to insert the same row twice esle we'll violate unique
557 my $rels_copied = {};
559 foreach my $rel ($self->result_source->relationships) {
560 my $rel_info = $self->result_source->relationship_info($rel);
562 next unless $rel_info->{attrs}{cascade_copy};
564 my $resolved = $self->result_source->resolve_condition(
565 $rel_info->{cond}, $rel, $new
568 my $copied = $rels_copied->{ $rel_info->{source} } ||= {};
569 foreach my $related ($self->search_related($rel)) {
570 my $id_str = join("\0", $related->id);
571 next if $copied->{$id_str};
572 $copied->{$id_str} = 1;
573 my $rel_copy = $related->copy($resolved);
582 $obj->store_column($col => $val);
584 Sets a column value without marking it as dirty.
589 my ($self, $column, $value) = @_;
590 $self->throw_exception( "No such column '${column}'" )
591 unless exists $self->{_column_data}{$column} || $self->has_column($column);
592 $self->throw_exception( "set_column called for ${column} without value" )
594 return $self->{_column_data}{$column} = $value;
597 =head2 inflate_result
599 Class->inflate_result($result_source, \%me, \%prefetch?)
601 Called by ResultSet to inflate a result from storage
606 my ($class, $source, $me, $prefetch) = @_;
608 my ($source_handle) = $source;
610 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
611 $source = $source_handle->resolve
613 $source_handle = $source->handle
617 _source_handle => $source_handle,
621 bless $new, (ref $class || $class);
624 foreach my $pre (keys %{$prefetch||{}}) {
625 my $pre_val = $prefetch->{$pre};
626 my $pre_source = $source->related_source($pre);
627 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
629 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
631 foreach my $pre_rec (@$pre_val) {
632 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
633 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
636 push(@pre_objects, $pre_source->result_class->inflate_result(
637 $pre_source, @{$pre_rec}));
639 $new->related_resultset($pre)->set_cache(\@pre_objects);
640 } elsif (defined $pre_val->[0]) {
642 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
643 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
645 $fetched = $pre_source->result_class->inflate_result(
646 $pre_source, @{$pre_val});
648 $new->related_resultset($pre)->set_cache([ $fetched ]);
649 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
650 $class->throw_exception("No accessor for prefetched $pre")
651 unless defined $accessor;
652 if ($accessor eq 'single') {
653 $new->{_relationship_data}{$pre} = $fetched;
654 } elsif ($accessor eq 'filter') {
655 $new->{_inflated_column}{$pre} = $fetched;
657 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
664 =head2 update_or_insert
666 $obj->update_or_insert
668 Updates the object if it's already in the db, else inserts it.
670 =head2 insert_or_update
672 $obj->insert_or_update
674 Alias for L</update_or_insert>
678 *insert_or_update = \&update_or_insert;
679 sub update_or_insert {
681 return ($self->in_storage ? $self->update : $self->insert);
686 my @changed_col_names = $obj->is_changed();
687 if ($obj->is_changed()) { ... }
689 In array context returns a list of columns with uncommited changes, or
690 in scalar context returns a true value if there are uncommitted
696 return keys %{shift->{_dirty_columns} || {}};
699 =head2 is_column_changed
701 if ($obj->is_column_changed('col')) { ... }
703 Returns a true value if the column has uncommitted changes.
707 sub is_column_changed {
708 my( $self, $col ) = @_;
709 return exists $self->{_dirty_columns}->{$col};
714 my $resultsource = $object->result_source;
716 Accessor to the ResultSource this object was created from
724 $self->_source_handle($_[0]->handle);
726 $self->_source_handle->resolve;
730 =head2 register_column
732 $column_info = { .... };
733 $class->register_column($column_name, $column_info);
735 Registers a column on the class. If the column_info has an 'accessor'
736 key, creates an accessor named after the value if defined; if there is
737 no such key, creates an accessor with the same name as the column
739 The column_info attributes are described in
740 L<DBIx::Class::ResultSource/add_columns>
744 sub register_column {
745 my ($class, $col, $info) = @_;
747 if (exists $info->{accessor}) {
748 return unless defined $info->{accessor};
749 $acc = [ $info->{accessor}, $col ];
751 $class->mk_group_accessors('column' => $acc);
755 =head2 throw_exception
757 See Schema's throw_exception.
761 sub throw_exception {
763 if (ref $self && ref $self->result_source && $self->result_source->schema) {
764 $self->result_source->schema->throw_exception(@_);
772 Returns the primary key(s) for a row. Can't be called as a class method.
773 Actually implemented in L<DBIx::Class::PK>
775 =head2 discard_changes
777 Re-selects the row from the database, losing any changes that had
780 This method can also be used to refresh from storage, retrieving any
781 changes made since the row was last read from storage. Actually
782 implemented in L<DBIx::Class::PK>
790 Matt S. Trout <mst@shadowcatsystems.co.uk>
794 You may distribute this code under the same terms as Perl itself.