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 To fetch an uninserted row object, call
144 L<new|DBIx::Class::ResultSet/new> on a resultset.
146 This will also insert any uninserted, related objects held inside this
147 one, see L<DBIx::Class::ResultSet/create> for more details.
153 return $self if $self->in_storage;
154 my $source = $self->result_source;
155 $source ||= $self->result_source($self->result_source_instance)
156 if $self->can('result_source_instance');
157 $self->throw_exception("No result_source set on this object; can't insert")
162 # Check if we stored uninserted relobjs here in new()
163 my %related_stuff = (%{$self->{_relationship_data} || {}},
164 %{$self->{_inflated_column} || {}});
166 if(!$self->{_rel_in_storage}) {
168 # The guard will save us if we blow out of this scope via die
169 $rollback_guard = $source->storage->txn_scope_guard;
171 ## Should all be in relationship_data, but we need to get rid of the
172 ## 'filter' reltype..
173 ## These are the FK rels, need their IDs for the insert.
175 my @pri = $self->primary_columns;
177 REL: foreach my $relname (keys %related_stuff) {
179 my $rel_obj = $related_stuff{$relname};
181 next REL unless (Scalar::Util::blessed($rel_obj)
182 && $rel_obj->isa('DBIx::Class::Row'));
184 my $cond = $source->relationship_info($relname)->{cond};
186 next REL unless ref($cond) eq 'HASH';
188 # map { foreign.foo => 'self.bar' } to { bar => 'foo' }
190 my $keyhash = { map { my $x = $_; $x =~ s/.*\.//; $x; } reverse %$cond };
192 # assume anything that references our PK probably is dependent on us
193 # rather than vice versa, unless the far side is (a) defined or (b)
196 foreach my $p (@pri) {
197 if (exists $keyhash->{$p}) {
198 unless (defined($rel_obj->get_column($keyhash->{$p}))
199 || $rel_obj->column_info($keyhash->{$p})
200 ->{is_auto_increment}) {
207 $self->set_from_related($relname, $rel_obj);
208 delete $related_stuff{$relname};
212 $source->storage->insert($source, { $self->get_columns });
215 my @auto_pri = grep {
216 !defined $self->get_column($_) ||
217 ref($self->get_column($_)) eq 'SCALAR'
218 } $self->primary_columns;
221 #$self->throw_exception( "More than one possible key found for auto-inc on ".ref $self )
222 # if defined $too_many;
224 my $storage = $self->result_source->storage;
225 $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" )
226 unless $storage->can('last_insert_id');
227 my @ids = $storage->last_insert_id($self->result_source,@auto_pri);
228 $self->throw_exception( "Can't get last insert id" )
229 unless (@ids == @auto_pri);
230 $self->store_column($auto_pri[$_] => $ids[$_]) for 0 .. $#ids;
233 if(!$self->{_rel_in_storage}) {
234 ## Now do the has_many rels, that need $selfs ID.
235 foreach my $relname (keys %related_stuff) {
236 my $rel_obj = $related_stuff{$relname};
238 if (Scalar::Util::blessed($rel_obj)
239 && $rel_obj->isa('DBIx::Class::Row')) {
241 } elsif (ref $rel_obj eq 'ARRAY') {
245 my $reverse = $source->reverse_relationship_info($relname);
246 foreach my $obj (@cands) {
247 $obj->set_from_related($_, $self) for keys %$reverse;
248 $obj->insert() unless ($obj->in_storage || $obj->result_source->resultset->search({$obj->get_columns})->count);
252 $rollback_guard->commit;
255 $self->in_storage(1);
256 $self->{_dirty_columns} = {};
257 $self->{related_resultsets} = {};
258 undef $self->{_orig_ident};
264 $obj->in_storage; # Get value
265 $obj->in_storage(1); # Set value
267 Indicates whether the object exists as a row in the database or
268 not. This is set to true when L<DBIx::Class::ResultSet/find>,
269 L<DBIx::Class::ResultSet/create> or L<DBIx::Class::ResultSet/insert>
272 Creating a row object using L<DBIx::Class::ResultSet/new>, or calling
273 L</delete> on one, sets it to false.
278 my ($self, $val) = @_;
279 $self->{_in_storage} = $val if @_ > 1;
280 return $self->{_in_storage};
285 $obj->update \%columns?;
287 Must be run on an object that is already in the database; issues an SQL
288 UPDATE query to commit any changes to the object to the database if
291 Also takes an options hashref of C<< column_name => value> pairs >> to update
292 first. But be aware that the hashref will be passed to
293 C<set_inflated_columns>, which might edit it in place, so dont rely on it being
294 the same after a call to C<update>. If you need to preserve the hashref, it is
295 sufficient to pass a shallow copy to C<update>, e.g. ( { %{ $href } } )
300 my ($self, $upd) = @_;
301 $self->throw_exception( "Not in database" ) unless $self->in_storage;
302 my $ident_cond = $self->ident_condition;
303 $self->throw_exception("Cannot safely update a row in a PK-less table")
304 if ! keys %$ident_cond;
306 $self->set_inflated_columns($upd) if $upd;
307 my %to_update = $self->get_dirty_columns;
308 return $self unless keys %to_update;
309 my $rows = $self->result_source->storage->update(
310 $self->result_source, \%to_update,
311 $self->{_orig_ident} || $ident_cond
314 $self->throw_exception( "Can't update ${self}: row not found" );
315 } elsif ($rows > 1) {
316 $self->throw_exception("Can't update ${self}: updated more than one row");
318 $self->{_dirty_columns} = {};
319 $self->{related_resultsets} = {};
320 undef $self->{_orig_ident};
328 Deletes the object from the database. The object is still perfectly
329 usable, but C<< ->in_storage() >> will now return 0 and the object must
330 reinserted using C<< ->insert() >> before C<< ->update() >> can be used
331 on it. If you delete an object in a class with a C<has_many>
332 relationship, all the related objects will be deleted as well. To turn
333 this behavior off, pass C<< cascade_delete => 0 >> in the C<$attr>
334 hashref. Any database-level cascade or restrict will take precedence
335 over a DBIx-Class-based cascading delete. See also L<DBIx::Class::ResultSet/delete>.
342 $self->throw_exception( "Not in database" ) unless $self->in_storage;
343 my $ident_cond = $self->ident_condition;
344 $self->throw_exception("Cannot safely delete a row in a PK-less table")
345 if ! keys %$ident_cond;
346 foreach my $column (keys %$ident_cond) {
347 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
348 unless exists $self->{_column_data}{$column};
350 $self->result_source->storage->delete(
351 $self->result_source, $ident_cond);
352 $self->in_storage(undef);
354 $self->throw_exception("Can't do class delete without a ResultSource instance")
355 unless $self->can('result_source_instance');
356 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
357 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
358 $self->result_source_instance->resultset->search(@_)->delete;
365 my $val = $obj->get_column($col);
367 Returns a raw column value from the row object, if it has already
368 been fetched from the database or set by an accessor.
370 If an L<inflated value|DBIx::Class::InflateColumn> has been set, it
371 will be deflated and returned.
376 my ($self, $column) = @_;
377 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
378 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
379 if (exists $self->{_inflated_column}{$column}) {
380 return $self->store_column($column,
381 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
383 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
387 =head2 has_column_loaded
389 if ( $obj->has_column_loaded($col) ) {
390 print "$col has been loaded from db";
393 Returns a true value if the column value has been loaded from the
394 database (or set locally).
398 sub has_column_loaded {
399 my ($self, $column) = @_;
400 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
401 return 1 if exists $self->{_inflated_column}{$column};
402 return exists $self->{_column_data}{$column};
407 my %data = $obj->get_columns;
409 Does C<get_column>, for all loaded column values at once.
415 if (exists $self->{_inflated_column}) {
416 foreach my $col (keys %{$self->{_inflated_column}}) {
417 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
418 unless exists $self->{_column_data}{$col};
421 return %{$self->{_column_data}};
424 =head2 get_dirty_columns
426 my %data = $obj->get_dirty_columns;
428 Identical to get_columns but only returns those that have been changed.
432 sub get_dirty_columns {
434 return map { $_ => $self->{_column_data}{$_} }
435 keys %{$self->{_dirty_columns}};
438 =head2 get_inflated_columns
440 my %inflated_data = $obj->get_inflated_columns;
442 Similar to get_columns but objects are returned for inflated columns
443 instead of their raw non-inflated values.
447 sub get_inflated_columns {
450 my $accessor = $self->column_info($_)->{'accessor'} || $_;
451 ($_ => $self->$accessor);
457 $obj->set_column($col => $val);
459 Sets a raw column value. If the new value is different from the old one,
460 the column is marked as dirty for when you next call $obj->update.
462 If passed an object or reference, this will happily attempt store the
463 value, and a later insert/update will try and stringify/numify as
471 $self->{_orig_ident} ||= $self->ident_condition;
472 my $old = $self->get_column($column);
473 my $ret = $self->store_column(@_);
474 $self->{_dirty_columns}{$column} = 1
475 if (defined $old xor defined $ret) || (defined $old && $old ne $ret);
477 # XXX clear out the relation cache for this column
478 delete $self->{related_resultsets}{$column};
485 my $copy = $orig->set_columns({ $col => $val, ... });
487 Sets more than one column value at once.
492 my ($self,$data) = @_;
493 foreach my $col (keys %$data) {
494 $self->set_column($col,$data->{$col});
499 =head2 set_inflated_columns
501 my $copy = $orig->set_inflated_columns({ $col => $val, $rel => $obj, ... });
503 Sets more than one column value at once, taking care to respect inflations and
504 relationships if relevant. Be aware that this hashref might be edited in place,
505 so dont rely on it being the same after a call to C<set_inflated_columns>. If
506 you need to preserve the hashref, it is sufficient to pass a shallow copy to
507 C<set_inflated_columns>, e.g. ( { %{ $href } } )
511 sub set_inflated_columns {
512 my ( $self, $upd ) = @_;
513 foreach my $key (keys %$upd) {
514 if (ref $upd->{$key}) {
515 my $info = $self->relationship_info($key);
516 if ($info && $info->{attrs}{accessor}
517 && $info->{attrs}{accessor} eq 'single')
519 my $rel = delete $upd->{$key};
520 $self->set_from_related($key => $rel);
521 $self->{_relationship_data}{$key} = $rel;
522 } elsif ($info && $info->{attrs}{accessor}
523 && $info->{attrs}{accessor} eq 'multi'
524 && ref $upd->{$key} eq 'ARRAY') {
525 my $others = delete $upd->{$key};
526 foreach my $rel_obj (@$others) {
527 if(!Scalar::Util::blessed($rel_obj)) {
528 $rel_obj = $self->create_related($key, $rel_obj);
531 $self->{_relationship_data}{$key} = $others;
532 # $related->{$key} = $others;
535 elsif ($self->has_column($key)
536 && exists $self->column_info($key)->{_inflate_info})
538 $self->set_inflated_column($key, delete $upd->{$key});
542 $self->set_columns($upd);
547 my $copy = $orig->copy({ change => $to, ... });
549 Inserts a new row with the specified changes.
554 my ($self, $changes) = @_;
556 my $col_data = { %{$self->{_column_data}} };
557 foreach my $col (keys %$col_data) {
558 delete $col_data->{$col}
559 if $self->result_source->column_info($col)->{is_auto_increment};
562 my $new = { _column_data => $col_data };
563 bless $new, ref $self;
565 $new->result_source($self->result_source);
566 $new->set_inflated_columns($changes);
569 # Its possible we'll have 2 relations to the same Source. We need to make
570 # sure we don't try to insert the same row twice esle we'll violate unique
572 my $rels_copied = {};
574 foreach my $rel ($self->result_source->relationships) {
575 my $rel_info = $self->result_source->relationship_info($rel);
577 next unless $rel_info->{attrs}{cascade_copy};
579 my $resolved = $self->result_source->resolve_condition(
580 $rel_info->{cond}, $rel, $new
583 my $copied = $rels_copied->{ $rel_info->{source} } ||= {};
584 foreach my $related ($self->search_related($rel)) {
585 my $id_str = join("\0", $related->id);
586 next if $copied->{$id_str};
587 $copied->{$id_str} = 1;
588 my $rel_copy = $related->copy($resolved);
597 $obj->store_column($col => $val);
599 Sets a column value without marking it as dirty.
604 my ($self, $column, $value) = @_;
605 $self->throw_exception( "No such column '${column}'" )
606 unless exists $self->{_column_data}{$column} || $self->has_column($column);
607 $self->throw_exception( "set_column called for ${column} without value" )
609 return $self->{_column_data}{$column} = $value;
612 =head2 inflate_result
614 Class->inflate_result($result_source, \%me, \%prefetch?)
616 Called by ResultSet to inflate a result from storage
621 my ($class, $source, $me, $prefetch) = @_;
623 my ($source_handle) = $source;
625 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
626 $source = $source_handle->resolve
628 $source_handle = $source->handle
632 _source_handle => $source_handle,
636 bless $new, (ref $class || $class);
639 foreach my $pre (keys %{$prefetch||{}}) {
640 my $pre_val = $prefetch->{$pre};
641 my $pre_source = $source->related_source($pre);
642 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
644 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
646 foreach my $pre_rec (@$pre_val) {
647 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
648 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
651 push(@pre_objects, $pre_source->result_class->inflate_result(
652 $pre_source, @{$pre_rec}));
654 $new->related_resultset($pre)->set_cache(\@pre_objects);
655 } elsif (defined $pre_val->[0]) {
657 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
658 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
660 $fetched = $pre_source->result_class->inflate_result(
661 $pre_source, @{$pre_val});
663 $new->related_resultset($pre)->set_cache([ $fetched ]);
664 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
665 $class->throw_exception("No accessor for prefetched $pre")
666 unless defined $accessor;
667 if ($accessor eq 'single') {
668 $new->{_relationship_data}{$pre} = $fetched;
669 } elsif ($accessor eq 'filter') {
670 $new->{_inflated_column}{$pre} = $fetched;
672 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
679 =head2 update_or_insert
681 $obj->update_or_insert
683 Updates the object if it's already in the database, according to
684 L</in_storage>, else inserts it.
686 =head2 insert_or_update
688 $obj->insert_or_update
690 Alias for L</update_or_insert>
694 *insert_or_update = \&update_or_insert;
695 sub update_or_insert {
697 return ($self->in_storage ? $self->update : $self->insert);
702 my @changed_col_names = $obj->is_changed();
703 if ($obj->is_changed()) { ... }
705 In array context returns a list of columns with uncommited changes, or
706 in scalar context returns a true value if there are uncommitted
712 return keys %{shift->{_dirty_columns} || {}};
715 =head2 is_column_changed
717 if ($obj->is_column_changed('col')) { ... }
719 Returns a true value if the column has uncommitted changes.
723 sub is_column_changed {
724 my( $self, $col ) = @_;
725 return exists $self->{_dirty_columns}->{$col};
730 my $resultsource = $object->result_source;
732 Accessor to the ResultSource this object was created from
740 $self->_source_handle($_[0]->handle);
742 $self->_source_handle->resolve;
746 =head2 register_column
748 $column_info = { .... };
749 $class->register_column($column_name, $column_info);
751 Registers a column on the class. If the column_info has an 'accessor'
752 key, creates an accessor named after the value if defined; if there is
753 no such key, creates an accessor with the same name as the column
755 The column_info attributes are described in
756 L<DBIx::Class::ResultSource/add_columns>
760 sub register_column {
761 my ($class, $col, $info) = @_;
763 if (exists $info->{accessor}) {
764 return unless defined $info->{accessor};
765 $acc = [ $info->{accessor}, $col ];
767 $class->mk_group_accessors('column' => $acc);
771 =head2 throw_exception
773 See Schema's throw_exception.
777 sub throw_exception {
779 if (ref $self && ref $self->result_source && $self->result_source->schema) {
780 $self->result_source->schema->throw_exception(@_);
788 Returns the primary key(s) for a row. Can't be called as a class method.
789 Actually implemented in L<DBIx::Class::PK>
791 =head2 discard_changes
793 Re-selects the row from the database, losing any changes that had
796 This method can also be used to refresh from storage, retrieving any
797 changes made since the row was last read from storage. Actually
798 implemented in L<DBIx::Class::PK>
806 Matt S. Trout <mst@shadowcatsystems.co.uk>
810 You may distribute this code under the same terms as Perl itself.