Merge 'DBIx-Class-current' into 'bulk_create'
[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}) {
108 $inflated->{$key} = $attrs->{$key};
109 next;
61a622ee 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 }
164
ac8e89d7 165 $source->storage->insert($source, { $self->get_columns });
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
c4a30d56 361database (or set locally).
9b83fccd 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
8091aa91 405=head2 set_column
7624b19f 406
407 $obj->set_column($col => $val);
408
8091aa91 409Sets a column value. If the new value is different from the old one,
410the column is marked as dirty for when you next call $obj->update.
7624b19f 411
412=cut
413
414sub set_column {
415 my $self = shift;
416 my ($column) = @_;
729b29ae 417 $self->{_orig_ident} ||= $self->ident_condition;
7624b19f 418 my $old = $self->get_column($column);
419 my $ret = $self->store_column(@_);
87772e46 420 $self->{_dirty_columns}{$column} = 1
421 if (defined $old ^ defined $ret) || (defined $old && $old ne $ret);
7624b19f 422 return $ret;
423}
424
8091aa91 425=head2 set_columns
076a6864 426
dc818523 427 my $copy = $orig->set_columns({ $col => $val, ... });
076a6864 428
8091aa91 429Sets more than one column value at once.
076a6864 430
431=cut
432
433sub set_columns {
434 my ($self,$data) = @_;
a2ca474b 435 foreach my $col (keys %$data) {
436 $self->set_column($col,$data->{$col});
076a6864 437 }
c01ab172 438 return $self;
076a6864 439}
440
8091aa91 441=head2 copy
076a6864 442
443 my $copy = $orig->copy({ change => $to, ... });
444
8091aa91 445Inserts a new row with the specified changes.
076a6864 446
447=cut
448
c01ab172 449sub copy {
450 my ($self, $changes) = @_;
333cce60 451 $changes ||= {};
fde6e28e 452 my $col_data = { %{$self->{_column_data}} };
453 foreach my $col (keys %$col_data) {
454 delete $col_data->{$col}
455 if $self->result_source->column_info($col)->{is_auto_increment};
456 }
04786a4c 457
458 my $new = { _column_data => $col_data };
459 bless $new, ref $self;
460
83419ec6 461 $new->result_source($self->result_source);
ecd1f408 462 $new->set_columns($changes);
333cce60 463 $new->insert;
464 foreach my $rel ($self->result_source->relationships) {
465 my $rel_info = $self->result_source->relationship_info($rel);
466 if ($rel_info->{attrs}{cascade_copy}) {
467 my $resolved = $self->result_source->resolve_condition(
468 $rel_info->{cond}, $rel, $new);
469 foreach my $related ($self->search_related($rel)) {
470 $related->copy($resolved);
471 }
472 }
473 }
2c4c67b6 474 return $new;
c01ab172 475}
476
8091aa91 477=head2 store_column
7624b19f 478
479 $obj->store_column($col => $val);
480
8091aa91 481Sets a column value without marking it as dirty.
7624b19f 482
483=cut
484
485sub store_column {
486 my ($self, $column, $value) = @_;
75d07914 487 $self->throw_exception( "No such column '${column}'" )
d7156e50 488 unless exists $self->{_column_data}{$column} || $self->has_column($column);
75d07914 489 $self->throw_exception( "set_column called for ${column} without value" )
7624b19f 490 if @_ < 3;
491 return $self->{_column_data}{$column} = $value;
492}
493
b52e9bf8 494=head2 inflate_result
495
c01ab172 496 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 497
498Called by ResultSet to inflate a result from storage
499
500=cut
501
502sub inflate_result {
c01ab172 503 my ($class, $source, $me, $prefetch) = @_;
aec3eff1 504
505 my ($source_handle) = $source;
506
507 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
508 $source = $source_handle->resolve
509 } else {
510 $source_handle = $source->handle
511 }
512
04786a4c 513 my $new = {
aec3eff1 514 _source_handle => $source_handle,
04786a4c 515 _column_data => $me,
516 _in_storage => 1
517 };
518 bless $new, (ref $class || $class);
519
7fb16f1a 520 my $schema;
64acc2bc 521 foreach my $pre (keys %{$prefetch||{}}) {
522 my $pre_val = $prefetch->{$pre};
f9cc31dd 523 my $pre_source = $source->related_source($pre);
a86b1efe 524 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
525 unless $pre_source;
0f66a01b 526 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
a86b1efe 527 my @pre_objects;
528 foreach my $pre_rec (@$pre_val) {
75d07914 529 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
5a5bec6c 530 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
a86b1efe 531 next;
532 }
533 push(@pre_objects, $pre_source->result_class->inflate_result(
534 $pre_source, @{$pre_rec}));
535 }
536 $new->related_resultset($pre)->set_cache(\@pre_objects);
62e87ea8 537 } elsif (defined $pre_val->[0]) {
a86b1efe 538 my $fetched;
75d07914 539 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
a86b1efe 540 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
541 {
542 $fetched = $pre_source->result_class->inflate_result(
75d07914 543 $pre_source, @{$pre_val});
a86b1efe 544 }
545 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
546 $class->throw_exception("No accessor for prefetched $pre")
547 unless defined $accessor;
548 if ($accessor eq 'single') {
549 $new->{_relationship_data}{$pre} = $fetched;
550 } elsif ($accessor eq 'filter') {
551 $new->{_inflated_column}{$pre} = $fetched;
552 } else {
553 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
554 }
b52e9bf8 555 }
556 }
7624b19f 557 return $new;
558}
559
9b465d00 560=head2 update_or_insert
7624b19f 561
9b465d00 562 $obj->update_or_insert
7624b19f 563
8091aa91 564Updates the object if it's already in the db, else inserts it.
7624b19f 565
9b83fccd 566=head2 insert_or_update
567
568 $obj->insert_or_update
569
570Alias for L</update_or_insert>
571
7624b19f 572=cut
573
9b465d00 574*insert_or_update = \&update_or_insert;
575sub update_or_insert {
7624b19f 576 my $self = shift;
577 return ($self->in_storage ? $self->update : $self->insert);
578}
579
8091aa91 580=head2 is_changed
7624b19f 581
228dbcb4 582 my @changed_col_names = $obj->is_changed();
583 if ($obj->is_changed()) { ... }
7624b19f 584
9b83fccd 585In array context returns a list of columns with uncommited changes, or
586in scalar context returns a true value if there are uncommitted
587changes.
588
7624b19f 589=cut
590
591sub is_changed {
592 return keys %{shift->{_dirty_columns} || {}};
593}
228dbcb4 594
595=head2 is_column_changed
596
597 if ($obj->is_column_changed('col')) { ... }
598
9b83fccd 599Returns a true value if the column has uncommitted changes.
600
228dbcb4 601=cut
602
603sub is_column_changed {
604 my( $self, $col ) = @_;
605 return exists $self->{_dirty_columns}->{$col};
606}
7624b19f 607
097d3227 608=head2 result_source
609
9b83fccd 610 my $resultsource = $object->result_source;
097d3227 611
9b83fccd 612Accessor to the ResultSource this object was created from
87c4e602 613
aec3eff1 614=cut
615
616sub result_source {
617 my $self = shift;
618
619 if (@_) {
620 $self->_source_handle($_[0]->handle);
621 } else {
622 $self->_source_handle->resolve;
623 }
624}
625
9b83fccd 626=head2 register_column
27f01d1f 627
9b83fccd 628 $column_info = { .... };
629 $class->register_column($column_name, $column_info);
27f01d1f 630
9b83fccd 631Registers a column on the class. If the column_info has an 'accessor'
632key, creates an accessor named after the value if defined; if there is
633no such key, creates an accessor with the same name as the column
1f23a877 634
9b83fccd 635The column_info attributes are described in
636L<DBIx::Class::ResultSource/add_columns>
1f23a877 637
097d3227 638=cut
639
1f23a877 640sub register_column {
641 my ($class, $col, $info) = @_;
91b0fbd7 642 my $acc = $col;
643 if (exists $info->{accessor}) {
644 return unless defined $info->{accessor};
645 $acc = [ $info->{accessor}, $col ];
646 }
647 $class->mk_group_accessors('column' => $acc);
1f23a877 648}
649
701da8c4 650
5160b401 651=head2 throw_exception
701da8c4 652
653See Schema's throw_exception.
654
655=cut
656
657sub throw_exception {
658 my $self=shift;
659 if (ref $self && ref $self->result_source) {
660 $self->result_source->schema->throw_exception(@_);
661 } else {
662 croak(@_);
663 }
664}
665
7624b19f 6661;
667
7624b19f 668=head1 AUTHORS
669
daec44b8 670Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 671
672=head1 LICENSE
673
674You may distribute this code under the same terms as Perl itself.
675
676=cut