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")
145 #use Data::Dumper; warn Dumper($self);
146 # Check if we stored uninserted relobjs here in new()
147 $source->storage->txn_begin if(!$self->{_rel_in_storage});
149 # Check if we stored uninserted relobjs here in new()
150 my %related_stuff = (%{$self->{_relationship_data} || {}},
151 %{$self->{_inflated_column} || {}});
152 if(!$self->{_rel_in_storage})
154 $source->storage->txn_begin;
156 ## Should all be in relationship_data, but we need to get rid of the
157 ## 'filter' reltype..
158 ## These are the FK rels, need their IDs for the insert.
159 foreach my $relname (keys %related_stuff) {
160 my $rel_obj = $related_stuff{$relname};
161 if(Scalar::Util::blessed($rel_obj) && $rel_obj->isa('DBIx::Class::Row')) {
163 $self->set_from_related($relname, $rel_obj);
168 $source->storage->insert($source, { $self->get_columns });
171 my ($pri, $too_many) = grep { !defined $self->get_column($_) ||
172 ref($self->get_column($_)) eq 'SCALAR'} $self->primary_columns;
174 $self->throw_exception( "More than one possible key found for auto-inc on ".ref $self )
175 if defined $too_many;
177 my $storage = $self->result_source->storage;
178 $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" )
179 unless $storage->can('last_insert_id');
180 my $id = $storage->last_insert_id($self->result_source,$pri);
181 $self->throw_exception( "Can't get last insert id" ) unless $id;
182 $self->store_column($pri => $id);
185 if(!$self->{_rel_in_storage})
187 ## Now do the has_many rels, that need $selfs ID.
188 foreach my $relname (keys %related_stuff) {
189 my $relobj = $related_stuff{$relname};
190 if(ref $relobj eq 'ARRAY') {
191 foreach my $obj (@$relobj) {
192 my $info = $self->relationship_info($relname);
193 ## What about multi-col FKs ?
194 my $key = $1 if($info && (keys %{$info->{cond}})[0] =~ /^foreign\.(\w+)/);
195 $obj->set_from_related($key, $self);
196 $obj->insert() if(!$obj->in_storage);
200 $source->storage->txn_commit;
203 $self->in_storage(1);
204 $self->{_dirty_columns} = {};
205 $self->{related_resultsets} = {};
206 undef $self->{_orig_ident};
212 $obj->in_storage; # Get value
213 $obj->in_storage(1); # Set value
215 Indicated whether the object exists as a row in the database or not
220 my ($self, $val) = @_;
221 $self->{_in_storage} = $val if @_ > 1;
222 return $self->{_in_storage};
227 $obj->update \%columns?;
229 Must be run on an object that is already in the database; issues an SQL
230 UPDATE query to commit any changes to the object to the database if
233 Also takes an options hashref of C<< column_name => value> pairs >> to update
234 first. But be aware that this hashref might be edited in place, so dont rely on
235 it being the same after a call to C<update>.
240 my ($self, $upd) = @_;
241 $self->throw_exception( "Not in database" ) unless $self->in_storage;
242 my $ident_cond = $self->ident_condition;
243 $self->throw_exception("Cannot safely update a row in a PK-less table")
244 if ! keys %$ident_cond;
247 foreach my $key (keys %$upd) {
248 if (ref $upd->{$key}) {
249 my $info = $self->relationship_info($key);
250 if ($info && $info->{attrs}{accessor}
251 && $info->{attrs}{accessor} eq 'single')
253 my $rel = delete $upd->{$key};
254 $self->set_from_related($key => $rel);
255 $self->{_relationship_data}{$key} = $rel;
256 } elsif ($info && $info->{attrs}{accessor}
257 && $info->{attrs}{accessor} eq 'multi'
258 && ref $upd->{$key} eq 'ARRAY') {
259 my $others = delete $upd->{$key};
260 foreach my $rel_obj (@$others) {
261 if(!Scalar::Util::blessed($rel_obj)) {
262 $rel_obj = $self->create_related($key, $rel_obj);
265 $self->{_relationship_data}{$key} = $others;
266 # $related->{$key} = $others;
269 elsif ($self->has_column($key)
270 && exists $self->column_info($key)->{_inflate_info})
272 $self->set_inflated_column($key, delete $upd->{$key});
276 $self->set_columns($upd);
278 my %to_update = $self->get_dirty_columns;
279 return $self unless keys %to_update;
280 my $rows = $self->result_source->storage->update(
281 $self->result_source, \%to_update,
282 $self->{_orig_ident} || $ident_cond
285 $self->throw_exception( "Can't update ${self}: row not found" );
286 } elsif ($rows > 1) {
287 $self->throw_exception("Can't update ${self}: updated more than one row");
289 $self->{_dirty_columns} = {};
290 $self->{related_resultsets} = {};
291 undef $self->{_orig_ident};
299 Deletes the object from the database. The object is still perfectly
300 usable, but C<< ->in_storage() >> will now return 0 and the object must
301 reinserted using C<< ->insert() >> before C<< ->update() >> can be used
302 on it. If you delete an object in a class with a C<has_many>
303 relationship, all the related objects will be deleted as well. To turn
304 this behavior off, pass C<cascade_delete => 0> in the C<$attr>
305 hashref. Any database-level cascade or restrict will take precedence
306 over a DBIx-Class-based cascading delete. See also L<DBIx::Class::ResultSet/delete>.
313 $self->throw_exception( "Not in database" ) unless $self->in_storage;
314 my $ident_cond = $self->ident_condition;
315 $self->throw_exception("Cannot safely delete a row in a PK-less table")
316 if ! keys %$ident_cond;
317 foreach my $column (keys %$ident_cond) {
318 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
319 unless exists $self->{_column_data}{$column};
321 $self->result_source->storage->delete(
322 $self->result_source, $ident_cond);
323 $self->in_storage(undef);
325 $self->throw_exception("Can't do class delete without a ResultSource instance")
326 unless $self->can('result_source_instance');
327 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
328 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
329 $self->result_source_instance->resultset->search(@_)->delete;
336 my $val = $obj->get_column($col);
338 Gets a column value from a row object. Does not do any queries; the column
339 must have already been fetched from the database and stored in the object. If
340 there is an inflated value stored that has not yet been deflated, it is deflated
341 when the method is invoked.
346 my ($self, $column) = @_;
347 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
348 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
349 if (exists $self->{_inflated_column}{$column}) {
350 return $self->store_column($column,
351 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
353 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
357 =head2 has_column_loaded
359 if ( $obj->has_column_loaded($col) ) {
360 print "$col has been loaded from db";
363 Returns a true value if the column value has been loaded from the
364 database (or set locally).
368 sub has_column_loaded {
369 my ($self, $column) = @_;
370 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
371 return 1 if exists $self->{_inflated_column}{$column};
372 return exists $self->{_column_data}{$column};
377 my %data = $obj->get_columns;
379 Does C<get_column>, for all column values at once.
385 if (exists $self->{_inflated_column}) {
386 foreach my $col (keys %{$self->{_inflated_column}}) {
387 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
388 unless exists $self->{_column_data}{$col};
391 return %{$self->{_column_data}};
394 =head2 get_dirty_columns
396 my %data = $obj->get_dirty_columns;
398 Identical to get_columns but only returns those that have been changed.
402 sub get_dirty_columns {
404 return map { $_ => $self->{_column_data}{$_} }
405 keys %{$self->{_dirty_columns}};
408 =head2 get_inflated_columns
410 my $inflated_data = $obj->get_inflated_columns;
412 Similar to get_columns but objects are returned for inflated columns instead of their raw non-inflated values.
416 sub get_inflated_columns {
419 my $accessor = $self->column_info($_)->{'accessor'} || $_;
420 ($_ => $self->$accessor);
426 $obj->set_column($col => $val);
428 Sets a column value. If the new value is different from the old one,
429 the column is marked as dirty for when you next call $obj->update.
436 $self->{_orig_ident} ||= $self->ident_condition;
437 my $old = $self->get_column($column);
438 my $ret = $self->store_column(@_);
439 $self->{_dirty_columns}{$column} = 1
440 if (defined $old ^ defined $ret) || (defined $old && $old ne $ret);
446 my $copy = $orig->set_columns({ $col => $val, ... });
448 Sets more than one column value at once.
453 my ($self,$data) = @_;
454 foreach my $col (keys %$data) {
455 $self->set_column($col,$data->{$col});
462 my $copy = $orig->copy({ change => $to, ... });
464 Inserts a new row with the specified changes.
469 my ($self, $changes) = @_;
471 my $col_data = { %{$self->{_column_data}} };
472 foreach my $col (keys %$col_data) {
473 delete $col_data->{$col}
474 if $self->result_source->column_info($col)->{is_auto_increment};
477 my $new = { _column_data => $col_data };
478 bless $new, ref $self;
480 $new->result_source($self->result_source);
481 $new->set_columns($changes);
483 foreach my $rel ($self->result_source->relationships) {
484 my $rel_info = $self->result_source->relationship_info($rel);
485 if ($rel_info->{attrs}{cascade_copy}) {
486 my $resolved = $self->result_source->resolve_condition(
487 $rel_info->{cond}, $rel, $new);
488 foreach my $related ($self->search_related($rel)) {
489 $related->copy($resolved);
498 $obj->store_column($col => $val);
500 Sets a column value without marking it as dirty.
505 my ($self, $column, $value) = @_;
506 $self->throw_exception( "No such column '${column}'" )
507 unless exists $self->{_column_data}{$column} || $self->has_column($column);
508 $self->throw_exception( "set_column called for ${column} without value" )
510 return $self->{_column_data}{$column} = $value;
513 =head2 inflate_result
515 Class->inflate_result($result_source, \%me, \%prefetch?)
517 Called by ResultSet to inflate a result from storage
522 my ($class, $source, $me, $prefetch) = @_;
524 my ($source_handle) = $source;
526 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
527 $source = $source_handle->resolve
529 $source_handle = $source->handle
533 _source_handle => $source_handle,
537 bless $new, (ref $class || $class);
540 foreach my $pre (keys %{$prefetch||{}}) {
541 my $pre_val = $prefetch->{$pre};
542 my $pre_source = $source->related_source($pre);
543 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
545 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
547 foreach my $pre_rec (@$pre_val) {
548 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
549 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
552 push(@pre_objects, $pre_source->result_class->inflate_result(
553 $pre_source, @{$pre_rec}));
555 $new->related_resultset($pre)->set_cache(\@pre_objects);
556 } elsif (defined $pre_val->[0]) {
558 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
559 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
561 $fetched = $pre_source->result_class->inflate_result(
562 $pre_source, @{$pre_val});
564 $new->related_resultset($pre)->set_cache([ $fetched ]);
565 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
566 $class->throw_exception("No accessor for prefetched $pre")
567 unless defined $accessor;
568 if ($accessor eq 'single') {
569 $new->{_relationship_data}{$pre} = $fetched;
570 } elsif ($accessor eq 'filter') {
571 $new->{_inflated_column}{$pre} = $fetched;
573 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
580 =head2 update_or_insert
582 $obj->update_or_insert
584 Updates the object if it's already in the db, else inserts it.
586 =head2 insert_or_update
588 $obj->insert_or_update
590 Alias for L</update_or_insert>
594 *insert_or_update = \&update_or_insert;
595 sub update_or_insert {
597 return ($self->in_storage ? $self->update : $self->insert);
602 my @changed_col_names = $obj->is_changed();
603 if ($obj->is_changed()) { ... }
605 In array context returns a list of columns with uncommited changes, or
606 in scalar context returns a true value if there are uncommitted
612 return keys %{shift->{_dirty_columns} || {}};
615 =head2 is_column_changed
617 if ($obj->is_column_changed('col')) { ... }
619 Returns a true value if the column has uncommitted changes.
623 sub is_column_changed {
624 my( $self, $col ) = @_;
625 return exists $self->{_dirty_columns}->{$col};
630 my $resultsource = $object->result_source;
632 Accessor to the ResultSource this object was created from
640 $self->_source_handle($_[0]->handle);
642 $self->_source_handle->resolve;
646 =head2 register_column
648 $column_info = { .... };
649 $class->register_column($column_name, $column_info);
651 Registers a column on the class. If the column_info has an 'accessor'
652 key, creates an accessor named after the value if defined; if there is
653 no such key, creates an accessor with the same name as the column
655 The column_info attributes are described in
656 L<DBIx::Class::ResultSource/add_columns>
660 sub register_column {
661 my ($class, $col, $info) = @_;
663 if (exists $info->{accessor}) {
664 return unless defined $info->{accessor};
665 $acc = [ $info->{accessor}, $col ];
667 $class->mk_group_accessors('column' => $acc);
671 =head2 throw_exception
673 See Schema's throw_exception.
677 sub throw_exception {
679 if (ref $self && ref $self->result_source) {
680 $self->result_source->schema->throw_exception(@_);
690 Matt S. Trout <mst@shadowcatsystems.co.uk>
694 You may distribute this code under the same terms as Perl itself.