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