1 package DBIx::Class::Row;
6 use base qw/DBIx::Class/;
7 use Carp::Clan qw/^DBIx::Class/;
10 __PACKAGE__->mk_group_accessors('simple' => qw/_source_handle/);
14 DBIx::Class::Row - Basic row methods
20 This class is responsible for defining and doing basic operations on rows
21 derived from L<DBIx::Class::ResultSource> objects.
27 my $obj = My::Class->new($attrs);
29 Creates a new row object from column => value mappings passed as a hash ref
31 Passing an object, or an arrayref of objects as a value will call
32 L<DBIx::Class::Relationship::Base/set_from_related> for you. When
33 passed a hashref or an arrayref of hashrefs as the value, these will
34 be turned into objects via new_related, and treated as if you had
39 ## 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().
40 ## This only works because DBIC doesnt yet care to check whether the new_related objects have been passed all their mandatory columns
41 ## When doing the later insert, we need to make sure the PKs are set.
42 ## using _relationship_data in new and funky ways..
43 ## check Relationship::CascadeActions and Relationship::Accessor for compat
47 my ($class, $attrs) = @_;
48 $class = ref $class if ref $class;
50 my $new = { _column_data => {} };
53 if (my $handle = delete $attrs->{-source_handle}) {
54 $new->_source_handle($handle);
56 if (my $source = delete $attrs->{-result_source}) {
57 $new->result_source($source);
61 $new->throw_exception("attrs must be a hashref")
62 unless ref($attrs) eq 'HASH';
64 my ($related,$inflated);
65 ## Pretend all the rels are actual objects, unset below if not, for insert() to fix
66 $new->{_rel_in_storage} = 1;
68 foreach my $key (keys %$attrs) {
69 if (ref $attrs->{$key}) {
70 ## Can we extract this lot to use with update(_or .. ) ?
71 my $info = $class->relationship_info($key);
72 if ($info && $info->{attrs}{accessor}
73 && $info->{attrs}{accessor} eq 'single')
75 my $rel_obj = delete $attrs->{$key};
76 if(!Scalar::Util::blessed($rel_obj)) {
77 $rel_obj = $new->find_or_new_related($key, $rel_obj);
78 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
80 $new->set_from_related($key, $rel_obj);
81 $related->{$key} = $rel_obj;
83 } elsif ($info && $info->{attrs}{accessor}
84 && $info->{attrs}{accessor} eq 'multi'
85 && ref $attrs->{$key} eq 'ARRAY') {
86 my $others = delete $attrs->{$key};
87 foreach my $rel_obj (@$others) {
88 if(!Scalar::Util::blessed($rel_obj)) {
89 $rel_obj = $new->new_related($key, $rel_obj);
90 $new->{_rel_in_storage} = 0;
93 $related->{$key} = $others;
95 } elsif ($info && $info->{attrs}{accessor}
96 && $info->{attrs}{accessor} eq 'filter')
98 ## 'filter' should disappear and get merged in with 'single' above!
99 my $rel_obj = delete $attrs->{$key};
100 if(!Scalar::Util::blessed($rel_obj)) {
101 $rel_obj = $new->find_or_new_related($key, $rel_obj);
102 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
104 $inflated->{$key} = $rel_obj;
106 } elsif ($class->has_column($key)
107 && $class->column_info($key)->{_inflate_info}) {
108 $inflated->{$key} = $attrs->{$key};
113 $new->throw_exception("No such column $key on $class")
114 unless $class->has_column($key);
115 $new->store_column($key => $attrs->{$key});
118 $new->{_relationship_data} = $related if $related;
119 $new->{_inflated_column} = $inflated if $inflated;
129 Inserts an object into the database if it isn't already in
130 there. Returns the object itself. Requires the object's result source to
131 be set, or the class to have a result_source_instance method. To insert
132 an entirely new object into the database, use C<create> (see
133 L<DBIx::Class::ResultSet/create>).
139 return $self if $self->in_storage;
140 my $source = $self->result_source;
141 $source ||= $self->result_source($self->result_source_instance)
142 if $self->can('result_source_instance');
143 $self->throw_exception("No result_source set on this object; can't insert")
146 # Check if we stored uninserted relobjs here in new()
147 my %related_stuff = (%{$self->{_relationship_data} || {}},
148 %{$self->{_inflated_column} || {}});
149 if(!$self->{_rel_in_storage})
151 $source->storage->txn_begin;
153 ## Should all be in relationship_data, but we need to get rid of the
154 ## 'filter' reltype..
155 ## These are the FK rels, need their IDs for the insert.
156 foreach my $relname (keys %related_stuff) {
157 my $rel_obj = $related_stuff{$relname};
158 if(Scalar::Util::blessed($rel_obj) && $rel_obj->isa('DBIx::Class::Row')) {
160 $self->set_from_related($relname, $rel_obj);
165 $source->storage->insert($source, { $self->get_columns });
168 my ($pri, $too_many) = grep { !defined $self->get_column($_) ||
169 ref($self->get_column($_)) eq 'SCALAR'} $self->primary_columns;
171 $self->throw_exception( "More than one possible key found for auto-inc on ".ref $self )
172 if defined $too_many;
174 my $storage = $self->result_source->storage;
175 $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" )
176 unless $storage->can('last_insert_id');
177 my $id = $storage->last_insert_id($self->result_source,$pri);
178 $self->throw_exception( "Can't get last insert id" ) unless $id;
179 $self->store_column($pri => $id);
182 if(!$self->{_rel_in_storage})
184 ## Now do the has_many rels, that need $selfs ID.
185 foreach my $relname (keys %related_stuff) {
186 my $relobj = $related_stuff{$relname};
187 if(ref $relobj eq 'ARRAY') {
188 foreach my $obj (@$relobj) {
189 my $info = $self->relationship_info($relname);
190 ## What about multi-col FKs ?
191 my $key = $1 if($info && (keys %{$info->{cond}})[0] =~ /^foreign\.(\w+)/);
192 $obj->set_from_related($key, $self);
193 $obj->insert() if(!$obj->in_storage);
197 $source->storage->txn_commit;
200 $self->in_storage(1);
201 $self->{_dirty_columns} = {};
202 $self->{related_resultsets} = {};
203 undef $self->{_orig_ident};
209 $obj->in_storage; # Get value
210 $obj->in_storage(1); # Set value
212 Indicated whether the object exists as a row in the database or not
217 my ($self, $val) = @_;
218 $self->{_in_storage} = $val if @_ > 1;
219 return $self->{_in_storage};
224 $obj->update \%columns?;
226 Must be run on an object that is already in the database; issues an SQL
227 UPDATE query to commit any changes to the object to the database if
230 Also takes an options hashref of C<< column_name => value> pairs >> to update
231 first. But be aware that this hashref might be edited in place, so dont rely on
232 it being the same after a call to C<update>. If you need to preserve the hashref,
233 it is sufficient to pass a shallow copy to C<update>, e.g. ( { %{ $href } } )
238 my ($self, $upd) = @_;
239 $self->throw_exception( "Not in database" ) unless $self->in_storage;
240 my $ident_cond = $self->ident_condition;
241 $self->throw_exception("Cannot safely update a row in a PK-less table")
242 if ! keys %$ident_cond;
245 foreach my $key (keys %$upd) {
246 if (ref $upd->{$key}) {
247 my $info = $self->relationship_info($key);
248 if ($info && $info->{attrs}{accessor}
249 && $info->{attrs}{accessor} eq 'single')
251 my $rel = delete $upd->{$key};
252 $self->set_from_related($key => $rel);
253 $self->{_relationship_data}{$key} = $rel;
254 } elsif ($info && $info->{attrs}{accessor}
255 && $info->{attrs}{accessor} eq 'multi'
256 && ref $upd->{$key} eq 'ARRAY') {
257 my $others = delete $upd->{$key};
258 foreach my $rel_obj (@$others) {
259 if(!Scalar::Util::blessed($rel_obj)) {
260 $rel_obj = $self->create_related($key, $rel_obj);
263 $self->{_relationship_data}{$key} = $others;
264 # $related->{$key} = $others;
267 elsif ($self->has_column($key)
268 && exists $self->column_info($key)->{_inflate_info})
270 $self->set_inflated_column($key, delete $upd->{$key});
274 $self->set_columns($upd);
276 my %to_update = $self->get_dirty_columns;
277 return $self unless keys %to_update;
278 my $rows = $self->result_source->storage->update(
279 $self->result_source, \%to_update,
280 $self->{_orig_ident} || $ident_cond
283 $self->throw_exception( "Can't update ${self}: row not found" );
284 } elsif ($rows > 1) {
285 $self->throw_exception("Can't update ${self}: updated more than one row");
287 $self->{_dirty_columns} = {};
288 $self->{related_resultsets} = {};
289 undef $self->{_orig_ident};
297 Deletes the object from the database. The object is still perfectly
298 usable, but C<< ->in_storage() >> will now return 0 and the object must
299 reinserted using C<< ->insert() >> before C<< ->update() >> can be used
300 on it. If you delete an object in a class with a C<has_many>
301 relationship, all the related objects will be deleted as well. To turn
302 this behavior off, pass C<cascade_delete => 0> in the C<$attr>
303 hashref. Any database-level cascade or restrict will take precedence
304 over a DBIx-Class-based cascading delete. See also L<DBIx::Class::ResultSet/delete>.
311 $self->throw_exception( "Not in database" ) unless $self->in_storage;
312 my $ident_cond = $self->ident_condition;
313 $self->throw_exception("Cannot safely delete a row in a PK-less table")
314 if ! keys %$ident_cond;
315 foreach my $column (keys %$ident_cond) {
316 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
317 unless exists $self->{_column_data}{$column};
319 $self->result_source->storage->delete(
320 $self->result_source, $ident_cond);
321 $self->in_storage(undef);
323 $self->throw_exception("Can't do class delete without a ResultSource instance")
324 unless $self->can('result_source_instance');
325 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
326 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
327 $self->result_source_instance->resultset->search(@_)->delete;
334 my $val = $obj->get_column($col);
336 Gets a column value from a row object. Does not do any queries; the column
337 must have already been fetched from the database and stored in the object. If
338 there is an inflated value stored that has not yet been deflated, it is deflated
339 when the method is invoked.
344 my ($self, $column) = @_;
345 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
346 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
347 if (exists $self->{_inflated_column}{$column}) {
348 return $self->store_column($column,
349 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
351 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
355 =head2 has_column_loaded
357 if ( $obj->has_column_loaded($col) ) {
358 print "$col has been loaded from db";
361 Returns a true value if the column value has been loaded from the
362 database (or set locally).
366 sub has_column_loaded {
367 my ($self, $column) = @_;
368 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
369 return 1 if exists $self->{_inflated_column}{$column};
370 return exists $self->{_column_data}{$column};
375 my %data = $obj->get_columns;
377 Does C<get_column>, for all column values at once.
383 if (exists $self->{_inflated_column}) {
384 foreach my $col (keys %{$self->{_inflated_column}}) {
385 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
386 unless exists $self->{_column_data}{$col};
389 return %{$self->{_column_data}};
392 =head2 get_dirty_columns
394 my %data = $obj->get_dirty_columns;
396 Identical to get_columns but only returns those that have been changed.
400 sub get_dirty_columns {
402 return map { $_ => $self->{_column_data}{$_} }
403 keys %{$self->{_dirty_columns}};
406 =head2 get_inflated_columns
408 my $inflated_data = $obj->get_inflated_columns;
410 Similar to get_columns but objects are returned for inflated columns instead of their raw non-inflated values.
414 sub get_inflated_columns {
417 my $accessor = $self->column_info($_)->{'accessor'} || $_;
418 ($_ => $self->$accessor);
424 $obj->set_column($col => $val);
426 Sets a column value. If the new value is different from the old one,
427 the column is marked as dirty for when you next call $obj->update.
434 $self->{_orig_ident} ||= $self->ident_condition;
435 my $old = $self->get_column($column);
436 my $ret = $self->store_column(@_);
437 $self->{_dirty_columns}{$column} = 1
438 if (defined $old ^ defined $ret) || (defined $old && $old ne $ret);
444 my $copy = $orig->set_columns({ $col => $val, ... });
446 Sets more than one column value at once.
451 my ($self,$data) = @_;
452 foreach my $col (keys %$data) {
453 $self->set_column($col,$data->{$col});
460 my $copy = $orig->copy({ change => $to, ... });
462 Inserts a new row with the specified changes.
467 my ($self, $changes) = @_;
469 my $col_data = { %{$self->{_column_data}} };
470 foreach my $col (keys %$col_data) {
471 delete $col_data->{$col}
472 if $self->result_source->column_info($col)->{is_auto_increment};
475 my $new = { _column_data => $col_data };
476 bless $new, ref $self;
478 $new->result_source($self->result_source);
479 $new->set_columns($changes);
481 foreach my $rel ($self->result_source->relationships) {
482 my $rel_info = $self->result_source->relationship_info($rel);
483 if ($rel_info->{attrs}{cascade_copy}) {
484 my $resolved = $self->result_source->resolve_condition(
485 $rel_info->{cond}, $rel, $new);
486 foreach my $related ($self->search_related($rel)) {
487 $related->copy($resolved);
496 $obj->store_column($col => $val);
498 Sets a column value without marking it as dirty.
503 my ($self, $column, $value) = @_;
504 $self->throw_exception( "No such column '${column}'" )
505 unless exists $self->{_column_data}{$column} || $self->has_column($column);
506 $self->throw_exception( "set_column called for ${column} without value" )
508 return $self->{_column_data}{$column} = $value;
511 =head2 inflate_result
513 Class->inflate_result($result_source, \%me, \%prefetch?)
515 Called by ResultSet to inflate a result from storage
520 my ($class, $source, $me, $prefetch) = @_;
522 my ($source_handle) = $source;
524 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
525 $source = $source_handle->resolve
527 $source_handle = $source->handle
531 _source_handle => $source_handle,
535 bless $new, (ref $class || $class);
538 foreach my $pre (keys %{$prefetch||{}}) {
539 my $pre_val = $prefetch->{$pre};
540 my $pre_source = $source->related_source($pre);
541 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
543 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
545 foreach my $pre_rec (@$pre_val) {
546 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
547 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
550 push(@pre_objects, $pre_source->result_class->inflate_result(
551 $pre_source, @{$pre_rec}));
553 $new->related_resultset($pre)->set_cache(\@pre_objects);
554 } elsif (defined $pre_val->[0]) {
556 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
557 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
559 $fetched = $pre_source->result_class->inflate_result(
560 $pre_source, @{$pre_val});
562 $new->related_resultset($pre)->set_cache([ $fetched ]);
563 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
564 $class->throw_exception("No accessor for prefetched $pre")
565 unless defined $accessor;
566 if ($accessor eq 'single') {
567 $new->{_relationship_data}{$pre} = $fetched;
568 } elsif ($accessor eq 'filter') {
569 $new->{_inflated_column}{$pre} = $fetched;
571 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
578 =head2 update_or_insert
580 $obj->update_or_insert
582 Updates the object if it's already in the db, else inserts it.
584 =head2 insert_or_update
586 $obj->insert_or_update
588 Alias for L</update_or_insert>
592 *insert_or_update = \&update_or_insert;
593 sub update_or_insert {
595 return ($self->in_storage ? $self->update : $self->insert);
600 my @changed_col_names = $obj->is_changed();
601 if ($obj->is_changed()) { ... }
603 In array context returns a list of columns with uncommited changes, or
604 in scalar context returns a true value if there are uncommitted
610 return keys %{shift->{_dirty_columns} || {}};
613 =head2 is_column_changed
615 if ($obj->is_column_changed('col')) { ... }
617 Returns a true value if the column has uncommitted changes.
621 sub is_column_changed {
622 my( $self, $col ) = @_;
623 return exists $self->{_dirty_columns}->{$col};
628 my $resultsource = $object->result_source;
630 Accessor to the ResultSource this object was created from
638 $self->_source_handle($_[0]->handle);
640 $self->_source_handle->resolve;
644 =head2 register_column
646 $column_info = { .... };
647 $class->register_column($column_name, $column_info);
649 Registers a column on the class. If the column_info has an 'accessor'
650 key, creates an accessor named after the value if defined; if there is
651 no such key, creates an accessor with the same name as the column
653 The column_info attributes are described in
654 L<DBIx::Class::ResultSource/add_columns>
658 sub register_column {
659 my ($class, $col, $info) = @_;
661 if (exists $info->{accessor}) {
662 return unless defined $info->{accessor};
663 $acc = [ $info->{accessor}, $col ];
665 $class->mk_group_accessors('column' => $acc);
669 =head2 throw_exception
671 See Schema's throw_exception.
675 sub throw_exception {
677 if (ref $self && ref $self->result_source) {
678 $self->result_source->schema->throw_exception(@_);
688 Matt S. Trout <mst@shadowcatsystems.co.uk>
692 You may distribute this code under the same terms as Perl itself.