error handling cleanup for _execute, etc
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Row.pm
CommitLineData
7624b19f 1package DBIx::Class::Row;
2
3use strict;
4use warnings;
5
1edd1722 6use base qw/DBIx::Class/;
701da8c4 7use Carp::Clan qw/^DBIx::Class/;
33dd4e80 8use Scalar::Util ();
1edd1722 9
aec3eff1 10__PACKAGE__->mk_group_accessors('simple' => qw/_source_handle/);
8c49f629 11
75d07914 12=head1 NAME
7624b19f 13
14DBIx::Class::Row - Basic row methods
15
16=head1 SYNOPSIS
17
18=head1 DESCRIPTION
19
20This class is responsible for defining and doing basic operations on rows
1ea77c14 21derived from L<DBIx::Class::ResultSource> objects.
7624b19f 22
23=head1 METHODS
24
8091aa91 25=head2 new
7624b19f 26
27 my $obj = My::Class->new($attrs);
28
29Creates a new row object from column => value mappings passed as a hash ref
30
33dd4e80 31Passing an object, or an arrayref of objects as a value will call
32L<DBIx::Class::Relationship::Base/set_from_related> for you. When
33passed a hashref or an arrayref of hashrefs as the value, these will
34be turned into objects via new_related, and treated as if you had
35passed objects.
36
7624b19f 37=cut
38
33dd4e80 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
44## tests!
45
7624b19f 46sub new {
448f820f 47 my ($class, $attrs) = @_;
7624b19f 48 $class = ref $class if ref $class;
04786a4c 49
50 my $new = { _column_data => {} };
51 bless $new, $class;
52
448f820f 53 if (my $handle = delete $attrs->{-source_handle}) {
54 $new->_source_handle($handle);
55 }
e9fe476b 56 if (my $source = delete $attrs->{-result_source}) {
57 $new->result_source($source);
58 }
a6a280b9 59
7624b19f 60 if ($attrs) {
27f01d1f 61 $new->throw_exception("attrs must be a hashref")
62 unless ref($attrs) eq 'HASH';
61a622ee 63
64 my ($related,$inflated);
de7c7c53 65 ## Pretend all the rels are actual objects, unset below if not, for insert() to fix
66 $new->{_rel_in_storage} = 1;
8222f722 67
61a622ee 68 foreach my $key (keys %$attrs) {
69 if (ref $attrs->{$key}) {
af2d42c0 70 ## Can we extract this lot to use with update(_or .. ) ?
61a622ee 71 my $info = $class->relationship_info($key);
72 if ($info && $info->{attrs}{accessor}
c4a30d56 73 && $info->{attrs}{accessor} eq 'single')
61a622ee 74 {
de7c7c53 75 my $rel_obj = delete $attrs->{$key};
33dd4e80 76 if(!Scalar::Util::blessed($rel_obj)) {
2ec8e594 77 $rel_obj = $new->find_or_new_related($key, $rel_obj);
78 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
33dd4e80 79 }
de7c7c53 80 $new->set_from_related($key, $rel_obj);
81 $related->{$key} = $rel_obj;
61a622ee 82 next;
33dd4e80 83 } elsif ($info && $info->{attrs}{accessor}
84 && $info->{attrs}{accessor} eq 'multi'
85 && ref $attrs->{$key} eq 'ARRAY') {
2ec8e594 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;
33dd4e80 91 }
2ec8e594 92 }
93 $related->{$key} = $others;
94 next;
95 } elsif ($info && $info->{attrs}{accessor}
96 && $info->{attrs}{accessor} eq 'filter')
61a622ee 97 {
33dd4e80 98 ## 'filter' should disappear and get merged in with 'single' above!
2ec8e594 99 my $rel_obj = delete $attrs->{$key};
33dd4e80 100 if(!Scalar::Util::blessed($rel_obj)) {
df78aeb1 101 $rel_obj = $new->find_or_new_related($key, $rel_obj);
102 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
33dd4e80 103 }
104 $inflated->{$key} = $rel_obj;
61a622ee 105 next;
2ec8e594 106 } elsif ($class->has_column($key)
107 && $class->column_info($key)->{_inflate_info}) {
61a622ee 108 $inflated->{$key} = $attrs->{$key};
109 next;
110 }
111 }
de7c7c53 112 use Data::Dumper;
61a622ee 113 $new->throw_exception("No such column $key on $class")
114 unless $class->has_column($key);
115 $new->store_column($key => $attrs->{$key});
7624b19f 116 }
f90375dd 117
61a622ee 118 $new->{_relationship_data} = $related if $related;
119 $new->{_inflated_column} = $inflated if $inflated;
7624b19f 120 }
04786a4c 121
7624b19f 122 return $new;
123}
124
8091aa91 125=head2 insert
7624b19f 126
127 $obj->insert;
128
b8810cc5 129Inserts an object into the database if it isn't already in
130there. Returns the object itself. Requires the object's result source to
131be set, or the class to have a result_source_instance method. To insert
132an entirely new object into the database, use C<create> (see
133L<DBIx::Class::ResultSet/create>).
7624b19f 134
135=cut
136
137sub insert {
138 my ($self) = @_;
139 return $self if $self->in_storage;
6aba697f 140 my $source = $self->result_source;
141 $source ||= $self->result_source($self->result_source_instance)
097d3227 142 if $self->can('result_source_instance');
aeb1bf75 143 $self->throw_exception("No result_source set on this object; can't insert")
144 unless $source;
6e399b4f 145
33dd4e80 146 # Check if we stored uninserted relobjs here in new()
33dd4e80 147 my %related_stuff = (%{$self->{_relationship_data} || {}},
148 %{$self->{_inflated_column} || {}});
8222f722 149 if(!$self->{_rel_in_storage})
150 {
151 $source->storage->txn_begin;
152
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')) {
159 $rel_obj->insert();
160 $self->set_from_related($relname, $rel_obj);
161 }
33dd4e80 162 }
163 }
6e399b4f 164
7af8b477 165 $source->storage->insert($source, { $self->get_columns });
ac8e89d7 166
167 ## PK::Auto
168 my ($pri, $too_many) = grep { !defined $self->get_column($_) ||
169 ref($self->get_column($_)) eq 'SCALAR'} $self->primary_columns;
170 if(defined $pri) {
171 $self->throw_exception( "More than one possible key found for auto-inc on ".ref $self )
172 if defined $too_many;
173
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);
180 }
33dd4e80 181
8222f722 182 if(!$self->{_rel_in_storage})
183 {
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);
194 }
33dd4e80 195 }
196 }
8222f722 197 $source->storage->txn_commit;
33dd4e80 198 }
33dd4e80 199
7624b19f 200 $self->in_storage(1);
201 $self->{_dirty_columns} = {};
64acc2bc 202 $self->{related_resultsets} = {};
729b29ae 203 undef $self->{_orig_ident};
7624b19f 204 return $self;
205}
206
8091aa91 207=head2 in_storage
7624b19f 208
209 $obj->in_storage; # Get value
210 $obj->in_storage(1); # Set value
211
212Indicated whether the object exists as a row in the database or not
213
214=cut
215
216sub in_storage {
217 my ($self, $val) = @_;
218 $self->{_in_storage} = $val if @_ > 1;
219 return $self->{_in_storage};
220}
221
8091aa91 222=head2 update
7624b19f 223
d5d833d9 224 $obj->update \%columns?;
7624b19f 225
226Must be run on an object that is already in the database; issues an SQL
d3b0e369 227UPDATE query to commit any changes to the object to the database if
228required.
7624b19f 229
d5d833d9 230Also takes an options hashref of C<< column_name => value> pairs >> to update
231first. But be aware that this hashref might be edited in place, so dont rely on
232it being the same after a call to C<update>.
233
7624b19f 234=cut
235
236sub update {
237 my ($self, $upd) = @_;
701da8c4 238 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 239 my $ident_cond = $self->ident_condition;
240 $self->throw_exception("Cannot safely update a row in a PK-less table")
241 if ! keys %$ident_cond;
6e399b4f 242
61a622ee 243 if ($upd) {
244 foreach my $key (keys %$upd) {
245 if (ref $upd->{$key}) {
246 my $info = $self->relationship_info($key);
247 if ($info && $info->{attrs}{accessor}
248 && $info->{attrs}{accessor} eq 'single')
249 {
250 my $rel = delete $upd->{$key};
251 $self->set_from_related($key => $rel);
252 $self->{_relationship_data}{$key} = $rel;
af2d42c0 253 } elsif ($info && $info->{attrs}{accessor}
254 && $info->{attrs}{accessor} eq 'multi'
255 && ref $upd->{$key} eq 'ARRAY') {
256 my $others = delete $upd->{$key};
257 foreach my $rel_obj (@$others) {
258 if(!Scalar::Util::blessed($rel_obj)) {
259 $rel_obj = $self->create_related($key, $rel_obj);
260 }
261 }
262 $self->{_relationship_data}{$key} = $others;
263# $related->{$key} = $others;
264 next;
265 }
61a622ee 266 elsif ($self->has_column($key)
267 && exists $self->column_info($key)->{_inflate_info})
268 {
269 $self->set_inflated_column($key, delete $upd->{$key});
270 }
271 }
272 }
273 $self->set_columns($upd);
274 }
5a9e0e60 275 my %to_update = $self->get_dirty_columns;
276 return $self unless keys %to_update;
88cb6a1d 277 my $rows = $self->result_source->storage->update(
f4afcd5d 278 $self->result_source, \%to_update,
279 $self->{_orig_ident} || $ident_cond
280 );
7624b19f 281 if ($rows == 0) {
701da8c4 282 $self->throw_exception( "Can't update ${self}: row not found" );
7624b19f 283 } elsif ($rows > 1) {
701da8c4 284 $self->throw_exception("Can't update ${self}: updated more than one row");
7624b19f 285 }
286 $self->{_dirty_columns} = {};
64acc2bc 287 $self->{related_resultsets} = {};
729b29ae 288 undef $self->{_orig_ident};
7624b19f 289 return $self;
290}
291
8091aa91 292=head2 delete
7624b19f 293
294 $obj->delete
295
b8810cc5 296Deletes the object from the database. The object is still perfectly
61a622ee 297usable, but C<< ->in_storage() >> will now return 0 and the object must
298reinserted using C<< ->insert() >> before C<< ->update() >> can be used
b8810cc5 299on it. If you delete an object in a class with a C<has_many>
300relationship, all the related objects will be deleted as well. To turn
301this behavior off, pass C<cascade_delete => 0> in the C<$attr>
302hashref. Any database-level cascade or restrict will take precedence
303over a DBIx-Class-based cascading delete. See also L<DBIx::Class::ResultSet/delete>.
7624b19f 304
305=cut
306
307sub delete {
308 my $self = shift;
309 if (ref $self) {
701da8c4 310 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 311 my $ident_cond = $self->ident_condition;
312 $self->throw_exception("Cannot safely delete a row in a PK-less table")
313 if ! keys %$ident_cond;
e0f56292 314 foreach my $column (keys %$ident_cond) {
75d07914 315 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
316 unless exists $self->{_column_data}{$column};
e0f56292 317 }
88cb6a1d 318 $self->result_source->storage->delete(
7af8b477 319 $self->result_source, $ident_cond);
7624b19f 320 $self->in_storage(undef);
7624b19f 321 } else {
701da8c4 322 $self->throw_exception("Can't do class delete without a ResultSource instance")
097d3227 323 unless $self->can('result_source_instance');
aeb1bf75 324 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
325 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
097d3227 326 $self->result_source_instance->resultset->search(@_)->delete;
7624b19f 327 }
328 return $self;
329}
330
8091aa91 331=head2 get_column
7624b19f 332
333 my $val = $obj->get_column($col);
334
61a622ee 335Gets a column value from a row object. Does not do any queries; the column
336must have already been fetched from the database and stored in the object. If
337there is an inflated value stored that has not yet been deflated, it is deflated
338when the method is invoked.
7624b19f 339
340=cut
341
342sub get_column {
343 my ($self, $column) = @_;
701da8c4 344 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
aeb1bf75 345 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
61a622ee 346 if (exists $self->{_inflated_column}{$column}) {
347 return $self->store_column($column,
348 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
349 }
701da8c4 350 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
7624b19f 351 return undef;
352}
353
9b83fccd 354=head2 has_column_loaded
355
356 if ( $obj->has_column_loaded($col) ) {
357 print "$col has been loaded from db";
358 }
359
360Returns a true value if the column value has been loaded from the
361database (or set locally).
362
363=cut
364
def81720 365sub has_column_loaded {
366 my ($self, $column) = @_;
367 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
61a622ee 368 return 1 if exists $self->{_inflated_column}{$column};
aeb1bf75 369 return exists $self->{_column_data}{$column};
def81720 370}
371
8091aa91 372=head2 get_columns
076a6864 373
374 my %data = $obj->get_columns;
375
8091aa91 376Does C<get_column>, for all column values at once.
076a6864 377
378=cut
379
380sub get_columns {
381 my $self = shift;
61a622ee 382 if (exists $self->{_inflated_column}) {
383 foreach my $col (keys %{$self->{_inflated_column}}) {
384 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
c4a30d56 385 unless exists $self->{_column_data}{$col};
61a622ee 386 }
387 }
cb5f2eea 388 return %{$self->{_column_data}};
d7156e50 389}
390
391=head2 get_dirty_columns
392
393 my %data = $obj->get_dirty_columns;
394
395Identical to get_columns but only returns those that have been changed.
396
397=cut
398
399sub get_dirty_columns {
400 my $self = shift;
401 return map { $_ => $self->{_column_data}{$_} }
402 keys %{$self->{_dirty_columns}};
076a6864 403}
404
ba4a6453 405=head2 get_inflated_columns
406
407 my $inflated_data = $obj->get_inflated_columns;
408
409Similar to get_columns but objects are returned for inflated columns instead of their raw non-inflated values.
410
411=cut
412
413sub get_inflated_columns {
414 my $self = shift;
415 return map {
416 my $accessor = $self->column_info($_)->{'accessor'} || $_;
417 ($_ => $self->$accessor);
418 } $self->columns;
419}
420
8091aa91 421=head2 set_column
7624b19f 422
423 $obj->set_column($col => $val);
424
8091aa91 425Sets a column value. If the new value is different from the old one,
426the column is marked as dirty for when you next call $obj->update.
7624b19f 427
428=cut
429
430sub set_column {
431 my $self = shift;
432 my ($column) = @_;
729b29ae 433 $self->{_orig_ident} ||= $self->ident_condition;
7624b19f 434 my $old = $self->get_column($column);
435 my $ret = $self->store_column(@_);
87772e46 436 $self->{_dirty_columns}{$column} = 1
437 if (defined $old ^ defined $ret) || (defined $old && $old ne $ret);
7624b19f 438 return $ret;
439}
440
8091aa91 441=head2 set_columns
076a6864 442
dc818523 443 my $copy = $orig->set_columns({ $col => $val, ... });
076a6864 444
8091aa91 445Sets more than one column value at once.
076a6864 446
447=cut
448
449sub set_columns {
450 my ($self,$data) = @_;
a2ca474b 451 foreach my $col (keys %$data) {
452 $self->set_column($col,$data->{$col});
076a6864 453 }
c01ab172 454 return $self;
076a6864 455}
456
8091aa91 457=head2 copy
076a6864 458
459 my $copy = $orig->copy({ change => $to, ... });
460
8091aa91 461Inserts a new row with the specified changes.
076a6864 462
463=cut
464
c01ab172 465sub copy {
466 my ($self, $changes) = @_;
333cce60 467 $changes ||= {};
fde6e28e 468 my $col_data = { %{$self->{_column_data}} };
469 foreach my $col (keys %$col_data) {
470 delete $col_data->{$col}
471 if $self->result_source->column_info($col)->{is_auto_increment};
472 }
04786a4c 473
474 my $new = { _column_data => $col_data };
475 bless $new, ref $self;
476
83419ec6 477 $new->result_source($self->result_source);
ecd1f408 478 $new->set_columns($changes);
333cce60 479 $new->insert;
480 foreach my $rel ($self->result_source->relationships) {
481 my $rel_info = $self->result_source->relationship_info($rel);
482 if ($rel_info->{attrs}{cascade_copy}) {
483 my $resolved = $self->result_source->resolve_condition(
484 $rel_info->{cond}, $rel, $new);
485 foreach my $related ($self->search_related($rel)) {
486 $related->copy($resolved);
487 }
488 }
489 }
2c4c67b6 490 return $new;
c01ab172 491}
492
8091aa91 493=head2 store_column
7624b19f 494
495 $obj->store_column($col => $val);
496
8091aa91 497Sets a column value without marking it as dirty.
7624b19f 498
499=cut
500
501sub store_column {
502 my ($self, $column, $value) = @_;
75d07914 503 $self->throw_exception( "No such column '${column}'" )
d7156e50 504 unless exists $self->{_column_data}{$column} || $self->has_column($column);
75d07914 505 $self->throw_exception( "set_column called for ${column} without value" )
7624b19f 506 if @_ < 3;
507 return $self->{_column_data}{$column} = $value;
508}
509
b52e9bf8 510=head2 inflate_result
511
c01ab172 512 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 513
514Called by ResultSet to inflate a result from storage
515
516=cut
517
518sub inflate_result {
c01ab172 519 my ($class, $source, $me, $prefetch) = @_;
aec3eff1 520
521 my ($source_handle) = $source;
522
523 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
524 $source = $source_handle->resolve
525 } else {
526 $source_handle = $source->handle
527 }
528
04786a4c 529 my $new = {
aec3eff1 530 _source_handle => $source_handle,
04786a4c 531 _column_data => $me,
532 _in_storage => 1
533 };
534 bless $new, (ref $class || $class);
535
7fb16f1a 536 my $schema;
64acc2bc 537 foreach my $pre (keys %{$prefetch||{}}) {
538 my $pre_val = $prefetch->{$pre};
f9cc31dd 539 my $pre_source = $source->related_source($pre);
a86b1efe 540 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
541 unless $pre_source;
0f66a01b 542 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
a86b1efe 543 my @pre_objects;
544 foreach my $pre_rec (@$pre_val) {
75d07914 545 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
5a5bec6c 546 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
a86b1efe 547 next;
548 }
549 push(@pre_objects, $pre_source->result_class->inflate_result(
550 $pre_source, @{$pre_rec}));
551 }
552 $new->related_resultset($pre)->set_cache(\@pre_objects);
62e87ea8 553 } elsif (defined $pre_val->[0]) {
a86b1efe 554 my $fetched;
75d07914 555 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
a86b1efe 556 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
557 {
558 $fetched = $pre_source->result_class->inflate_result(
75d07914 559 $pre_source, @{$pre_val});
a86b1efe 560 }
9809a6df 561 $new->related_resultset($pre)->set_cache([ $fetched ]);
a86b1efe 562 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
563 $class->throw_exception("No accessor for prefetched $pre")
564 unless defined $accessor;
565 if ($accessor eq 'single') {
566 $new->{_relationship_data}{$pre} = $fetched;
567 } elsif ($accessor eq 'filter') {
568 $new->{_inflated_column}{$pre} = $fetched;
569 } else {
570 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
571 }
b52e9bf8 572 }
573 }
7624b19f 574 return $new;
575}
576
9b465d00 577=head2 update_or_insert
7624b19f 578
9b465d00 579 $obj->update_or_insert
7624b19f 580
8091aa91 581Updates the object if it's already in the db, else inserts it.
7624b19f 582
9b83fccd 583=head2 insert_or_update
584
585 $obj->insert_or_update
586
587Alias for L</update_or_insert>
588
7624b19f 589=cut
590
9b465d00 591*insert_or_update = \&update_or_insert;
592sub update_or_insert {
7624b19f 593 my $self = shift;
594 return ($self->in_storage ? $self->update : $self->insert);
595}
596
8091aa91 597=head2 is_changed
7624b19f 598
228dbcb4 599 my @changed_col_names = $obj->is_changed();
600 if ($obj->is_changed()) { ... }
7624b19f 601
9b83fccd 602In array context returns a list of columns with uncommited changes, or
603in scalar context returns a true value if there are uncommitted
604changes.
605
7624b19f 606=cut
607
608sub is_changed {
609 return keys %{shift->{_dirty_columns} || {}};
610}
228dbcb4 611
612=head2 is_column_changed
613
614 if ($obj->is_column_changed('col')) { ... }
615
9b83fccd 616Returns a true value if the column has uncommitted changes.
617
228dbcb4 618=cut
619
620sub is_column_changed {
621 my( $self, $col ) = @_;
622 return exists $self->{_dirty_columns}->{$col};
623}
7624b19f 624
097d3227 625=head2 result_source
626
9b83fccd 627 my $resultsource = $object->result_source;
097d3227 628
9b83fccd 629Accessor to the ResultSource this object was created from
87c4e602 630
aec3eff1 631=cut
632
633sub result_source {
634 my $self = shift;
635
636 if (@_) {
637 $self->_source_handle($_[0]->handle);
638 } else {
639 $self->_source_handle->resolve;
640 }
641}
642
9b83fccd 643=head2 register_column
27f01d1f 644
9b83fccd 645 $column_info = { .... };
646 $class->register_column($column_name, $column_info);
27f01d1f 647
9b83fccd 648Registers a column on the class. If the column_info has an 'accessor'
649key, creates an accessor named after the value if defined; if there is
650no such key, creates an accessor with the same name as the column
1f23a877 651
9b83fccd 652The column_info attributes are described in
653L<DBIx::Class::ResultSource/add_columns>
1f23a877 654
097d3227 655=cut
656
1f23a877 657sub register_column {
658 my ($class, $col, $info) = @_;
91b0fbd7 659 my $acc = $col;
660 if (exists $info->{accessor}) {
661 return unless defined $info->{accessor};
662 $acc = [ $info->{accessor}, $col ];
663 }
664 $class->mk_group_accessors('column' => $acc);
1f23a877 665}
666
701da8c4 667
5160b401 668=head2 throw_exception
701da8c4 669
670See Schema's throw_exception.
671
672=cut
673
674sub throw_exception {
675 my $self=shift;
676 if (ref $self && ref $self->result_source) {
677 $self->result_source->schema->throw_exception(@_);
678 } else {
679 croak(@_);
680 }
681}
682
7624b19f 6831;
684
7624b19f 685=head1 AUTHORS
686
daec44b8 687Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 688
689=head1 LICENSE
690
691You may distribute this code under the same terms as Perl itself.
692
693=cut