1 package DBIx::Class::Row;
6 use base qw/DBIx::Class/;
7 use Carp::Clan qw/^DBIx::Class/;
9 __PACKAGE__->load_components(qw/AccessorGroup/);
11 __PACKAGE__->mk_group_accessors('simple' => 'result_source');
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
35 my ($class, $attrs) = @_;
36 $class = ref $class if ref $class;
38 my $new = { _column_data => {} };
42 $new->throw_exception("attrs must be a hashref")
43 unless ref($attrs) eq 'HASH';
44 foreach my $k (keys %$attrs) {
45 $new->throw_exception("No such column $k on $class")
46 unless $class->has_column($k);
47 $new->store_column($k => $attrs->{$k});
58 Inserts an object into the database if it isn't already in
59 there. Returns the object itself. Requires the object's result source to
60 be set, or the class to have a result_source_instance method. To insert
61 an entirely new object into the database, use C<create> (see
62 L<DBIx::Class::ResultSet/create>).
68 return $self if $self->in_storage;
69 $self->{result_source} ||= $self->result_source_instance
70 if $self->can('result_source_instance');
71 my $source = $self->{result_source};
72 $self->throw_exception("No result_source set on this object; can't insert")
74 #use Data::Dumper; warn Dumper($self);
75 $source->storage->insert($source->from, { $self->get_columns });
77 $self->{_dirty_columns} = {};
78 $self->{related_resultsets} = {};
84 $obj->in_storage; # Get value
85 $obj->in_storage(1); # Set value
87 Indicated whether the object exists as a row in the database or not
92 my ($self, $val) = @_;
93 $self->{_in_storage} = $val if @_ > 1;
94 return $self->{_in_storage};
101 Must be run on an object that is already in the database; issues an SQL
102 UPDATE query to commit any changes to the object to the database if
108 my ($self, $upd) = @_;
109 $self->throw_exception( "Not in database" ) unless $self->in_storage;
110 $self->set_columns($upd) if $upd;
111 my %to_update = $self->get_dirty_columns;
112 return $self unless keys %to_update;
113 my $ident_cond = $self->ident_condition;
114 $self->throw_exception("Cannot safely update a row in a PK-less table")
115 if ! keys %$ident_cond;
116 my $rows = $self->result_source->storage->update(
117 $self->result_source->from, \%to_update, $ident_cond);
119 $self->throw_exception( "Can't update ${self}: row not found" );
120 } elsif ($rows > 1) {
121 $self->throw_exception("Can't update ${self}: updated more than one row");
123 $self->{_dirty_columns} = {};
124 $self->{related_resultsets} = {};
132 Deletes the object from the database. The object is still perfectly
133 usable, but C<-E<gt>in_storage()> will now return 0 and the object must
134 reinserted using C<-E<gt>insert()> before C<-E(<gt>update()> can be used
135 on it. If you delete an object in a class with a C<has_many>
136 relationship, all the related objects will be deleted as well. To turn
137 this behavior off, pass C<cascade_delete => 0> in the C<$attr>
138 hashref. Any database-level cascade or restrict will take precedence
139 over a DBIx-Class-based cascading delete. See also L<DBIx::Class::ResultSet/delete>.
146 $self->throw_exception( "Not in database" ) unless $self->in_storage;
147 my $ident_cond = $self->ident_condition;
148 $self->throw_exception("Cannot safely delete a row in a PK-less table")
149 if ! keys %$ident_cond;
150 foreach my $column (keys %$ident_cond) {
151 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
152 unless exists $self->{_column_data}{$column};
154 $self->result_source->storage->delete(
155 $self->result_source->from, $ident_cond);
156 $self->in_storage(undef);
158 $self->throw_exception("Can't do class delete without a ResultSource instance")
159 unless $self->can('result_source_instance');
160 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
161 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
162 $self->result_source_instance->resultset->search(@_)->delete;
169 my $val = $obj->get_column($col);
171 Gets a column value from a row object. Currently, does not do
172 any queries; the column must have already been fetched from
173 the database and stored in the object.
178 my ($self, $column) = @_;
179 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
180 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
181 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
185 =head2 has_column_loaded
187 if ( $obj->has_column_loaded($col) ) {
188 print "$col has been loaded from db";
191 Returns a true value if the column value has been loaded from the
192 database (or set locally).
196 sub has_column_loaded {
197 my ($self, $column) = @_;
198 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
199 return exists $self->{_column_data}{$column};
204 my %data = $obj->get_columns;
206 Does C<get_column>, for all column values at once.
212 return %{$self->{_column_data}};
215 =head2 get_dirty_columns
217 my %data = $obj->get_dirty_columns;
219 Identical to get_columns but only returns those that have been changed.
223 sub get_dirty_columns {
225 return map { $_ => $self->{_column_data}{$_} }
226 keys %{$self->{_dirty_columns}};
231 $obj->set_column($col => $val);
233 Sets a column value. If the new value is different from the old one,
234 the column is marked as dirty for when you next call $obj->update.
241 my $old = $self->get_column($column);
242 my $ret = $self->store_column(@_);
243 $self->{_dirty_columns}{$column} = 1
244 if (defined $old ^ defined $ret) || (defined $old && $old ne $ret);
250 my $copy = $orig->set_columns({ $col => $val, ... });
252 Sets more than one column value at once.
257 my ($self,$data) = @_;
258 foreach my $col (keys %$data) {
259 $self->set_column($col,$data->{$col});
266 my $copy = $orig->copy({ change => $to, ... });
268 Inserts a new row with the specified changes.
273 my ($self, $changes) = @_;
275 my $col_data = { %{$self->{_column_data}} };
276 foreach my $col (keys %$col_data) {
277 delete $col_data->{$col}
278 if $self->result_source->column_info($col)->{is_auto_increment};
281 my $new = { _column_data => $col_data };
282 bless $new, ref $self;
284 $new->result_source($self->result_source);
285 $new->set_columns($changes);
287 foreach my $rel ($self->result_source->relationships) {
288 my $rel_info = $self->result_source->relationship_info($rel);
289 if ($rel_info->{attrs}{cascade_copy}) {
290 my $resolved = $self->result_source->resolve_condition(
291 $rel_info->{cond}, $rel, $new);
292 foreach my $related ($self->search_related($rel)) {
293 $related->copy($resolved);
302 $obj->store_column($col => $val);
304 Sets a column value without marking it as dirty.
309 my ($self, $column, $value) = @_;
310 $self->throw_exception( "No such column '${column}'" )
311 unless exists $self->{_column_data}{$column} || $self->has_column($column);
312 $self->throw_exception( "set_column called for ${column} without value" )
314 return $self->{_column_data}{$column} = $value;
317 =head2 inflate_result
319 Class->inflate_result($result_source, \%me, \%prefetch?)
321 Called by ResultSet to inflate a result from storage
326 my ($class, $source, $me, $prefetch) = @_;
327 #use Data::Dumper; print Dumper(@_);
329 result_source => $source,
333 bless $new, (ref $class || $class);
336 foreach my $pre (keys %{$prefetch||{}}) {
337 my $pre_val = $prefetch->{$pre};
338 my $pre_source = $source->related_source($pre);
339 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
341 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
343 foreach my $pre_rec (@$pre_val) {
344 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
345 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
348 push(@pre_objects, $pre_source->result_class->inflate_result(
349 $pre_source, @{$pre_rec}));
351 $new->related_resultset($pre)->set_cache(\@pre_objects);
352 } elsif (defined $pre_val->[0]) {
354 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
355 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
357 $fetched = $pre_source->result_class->inflate_result(
358 $pre_source, @{$pre_val});
360 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
361 $class->throw_exception("No accessor for prefetched $pre")
362 unless defined $accessor;
363 if ($accessor eq 'single') {
364 $new->{_relationship_data}{$pre} = $fetched;
365 } elsif ($accessor eq 'filter') {
366 $new->{_inflated_column}{$pre} = $fetched;
368 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
375 =head2 update_or_insert
377 $obj->update_or_insert
379 Updates the object if it's already in the db, else inserts it.
381 =head2 insert_or_update
383 $obj->insert_or_update
385 Alias for L</update_or_insert>
389 *insert_or_update = \&update_or_insert;
390 sub update_or_insert {
392 return ($self->in_storage ? $self->update : $self->insert);
397 my @changed_col_names = $obj->is_changed();
398 if ($obj->is_changed()) { ... }
400 In array context returns a list of columns with uncommited changes, or
401 in scalar context returns a true value if there are uncommitted
407 return keys %{shift->{_dirty_columns} || {}};
410 =head2 is_column_changed
412 if ($obj->is_column_changed('col')) { ... }
414 Returns a true value if the column has uncommitted changes.
418 sub is_column_changed {
419 my( $self, $col ) = @_;
420 return exists $self->{_dirty_columns}->{$col};
425 my $resultsource = $object->result_source;
427 Accessor to the ResultSource this object was created from
429 =head2 register_column
431 $column_info = { .... };
432 $class->register_column($column_name, $column_info);
434 Registers a column on the class. If the column_info has an 'accessor'
435 key, creates an accessor named after the value if defined; if there is
436 no such key, creates an accessor with the same name as the column
438 The column_info attributes are described in
439 L<DBIx::Class::ResultSource/add_columns>
443 sub register_column {
444 my ($class, $col, $info) = @_;
446 if (exists $info->{accessor}) {
447 return unless defined $info->{accessor};
448 $acc = [ $info->{accessor}, $col ];
450 $class->mk_group_accessors('column' => $acc);
454 =head2 throw_exception
456 See Schema's throw_exception.
460 sub throw_exception {
462 if (ref $self && ref $self->result_source) {
463 $self->result_source->schema->throw_exception(@_);
473 Matt S. Trout <mst@shadowcatsystems.co.uk>
477 You may distribute this code under the same terms as Perl itself.