missed a couple things
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSource.pm
CommitLineData
9c992ba1 1package DBIx::Class::ResultSource;
2
3use strict;
4use warnings;
5
6use DBIx::Class::ResultSet;
701da8c4 7use Carp::Clan qw/^DBIx::Class/;
6da5894c 8use Storable;
9
9c992ba1 10use base qw/DBIx::Class/;
11__PACKAGE__->load_components(qw/AccessorGroup/);
12
aa1088bf 13__PACKAGE__->mk_group_accessors('simple' => qw/_ordered_columns
14 _columns _primaries _unique_constraints name resultset_attributes
15 schema from _relationships/);
16
17__PACKAGE__->mk_group_accessors('component_class' => qw/resultset_class
18 result_class/);
9c992ba1 19
20=head1 NAME
21
22DBIx::Class::ResultSource - Result source object
23
24=head1 SYNOPSIS
25
26=head1 DESCRIPTION
27
28A ResultSource is a component of a schema from which results can be directly
29retrieved, most usually a table (see L<DBIx::Class::ResultSource::Table>)
30
31=head1 METHODS
32
33=cut
34
35sub new {
36 my ($class, $attrs) = @_;
37 $class = ref $class if ref $class;
1225fc4d 38 my $new = bless({ %{$attrs || {}}, _resultset => undef }, $class);
9c992ba1 39 $new->{resultset_class} ||= 'DBIx::Class::ResultSet';
5ac6a044 40 $new->{resultset_attributes} = { %{$new->{resultset_attributes} || {}} };
6da5894c 41 $new->{_ordered_columns} = [ @{$new->{_ordered_columns}||[]}];
42 $new->{_columns} = { %{$new->{_columns}||{}} };
43 $new->{_relationships} = { %{$new->{_relationships}||{}} };
9c992ba1 44 $new->{name} ||= "!!NAME NOT SET!!";
5afa2a15 45 $new->{_columns_info_loaded} ||= 0;
9c992ba1 46 return $new;
47}
48
988bf309 49=pod
50
5ac6a044 51=head2 add_columns
52
53 $table->add_columns(qw/col1 col2 col3/);
54
55 $table->add_columns('col1' => \%col1_info, 'col2' => \%col2_info, ...);
56
2053ab2a 57Adds columns to the result source. If supplied key => hashref pairs, uses
58the hashref as the column_info for that column. Repeated calls of this
59method will add more columns, not replace them.
5ac6a044 60
2053ab2a 61The contents of the column_info are not set in stone. The following
62keys are currently recognised/used by DBIx::Class:
988bf309 63
64=over 4
65
66=item accessor
67
68Use this to set the name of the accessor for this column. If unset,
69the name of the column will be used.
70
71=item data_type
72
2053ab2a 73This contains the column type. It is automatically filled by the
988bf309 74L<SQL::Translator::Producer::DBIx::Class::File> producer, and the
2053ab2a 75L<DBIx::Class::Schema::Loader> module. If you do not enter a
988bf309 76data_type, DBIx::Class will attempt to retrieve it from the
2053ab2a 77database for you, using L<DBI>'s column_info method. The values of this
988bf309 78key are typically upper-cased.
79
2053ab2a 80Currently there is no standard set of values for the data_type. Use
81whatever your database supports.
988bf309 82
83=item size
84
85The length of your column, if it is a column type that can have a size
86restriction. This is currently not used by DBIx::Class.
87
88=item is_nullable
89
2053ab2a 90Set this to a true value for a columns that is allowed to contain
91NULL values. This is currently not used by DBIx::Class.
988bf309 92
93=item is_auto_increment
94
2053ab2a 95Set this to a true value for a column whose value is somehow
96automatically set. This is used to determine which columns to empty
e666492c 97when cloning objects using C<copy>.
988bf309 98
99=item is_foreign_key
100
2053ab2a 101Set this to a true value for a column that contains a key from a
988bf309 102foreign table. This is currently not used by DBIx::Class.
103
104=item default_value
105
2053ab2a 106Set this to the default value which will be inserted into a column
107by the database. Can contain either a value or a function. This is
988bf309 108currently not used by DBIx::Class.
109
110=item sequence
111
2053ab2a 112Set this on a primary key column to the name of the sequence used to
113generate a new key value. If not specified, L<DBIx::Class::PK::Auto>
114will attempt to retrieve the name of the sequence from the database
115automatically.
988bf309 116
117=back
118
5ac6a044 119=head2 add_column
120
121 $table->add_column('col' => \%info?);
122
2053ab2a 123Convenience alias to add_columns.
5ac6a044 124
125=cut
126
9c992ba1 127sub add_columns {
128 my ($self, @cols) = @_;
8e04bf91 129 $self->_ordered_columns(\@cols) unless $self->_ordered_columns;
130
20518cb4 131 my @added;
132 my $columns = $self->_columns;
9c992ba1 133 while (my $col = shift @cols) {
8e04bf91 134 # If next entry is { ... } use that for the column info, if not
135 # use an empty hashref
30126ac7 136 my $column_info = ref $cols[0] ? shift(@cols) : {};
20518cb4 137 push(@added, $col) unless exists $columns->{$col};
20518cb4 138 $columns->{$col} = $column_info;
9c992ba1 139 }
20518cb4 140 push @{ $self->_ordered_columns }, @added;
30126ac7 141 return $self;
9c992ba1 142}
143
144*add_column = \&add_columns;
145
3842b955 146=head2 has_column
147
988bf309 148 if ($obj->has_column($col)) { ... }
149
2053ab2a 150Returns true if the source has a column of this name, false otherwise.
988bf309 151
152=cut
9c992ba1 153
154sub has_column {
155 my ($self, $column) = @_;
156 return exists $self->_columns->{$column};
157}
158
87c4e602 159=head2 column_info
9c992ba1 160
988bf309 161 my $info = $obj->column_info($col);
9c992ba1 162
988bf309 163Returns the column metadata hashref for a column. See the description
164of add_column for information on the contents of the hashref.
9c992ba1 165
988bf309 166=cut
9c992ba1 167
168sub column_info {
169 my ($self, $column) = @_;
701da8c4 170 $self->throw_exception("No such column $column")
171 unless exists $self->_columns->{$column};
5afa2a15 172 #warn $self->{_columns_info_loaded}, "\n";
8e04bf91 173 if ( ! $self->_columns->{$column}{data_type}
174 and ! $self->{_columns_info_loaded}
175 and $self->schema and $self->storage )
176 {
177 $self->{_columns_info_loaded}++;
178 my $info;
179 # eval for the case of storage without table
180 eval { $info = $self->storage->columns_info_for($self->from) };
181 unless ($@) {
182 foreach my $col ( keys %{$self->_columns} ) {
183 foreach my $i ( keys %{$info->{$col}} ) {
184 $self->_columns->{$col}{$i} = $info->{$col}{$i};
185 }
a953d8d9 186 }
8e04bf91 187 }
a953d8d9 188 }
9c992ba1 189 return $self->_columns->{$column};
190}
191
192=head2 columns
193
20518cb4 194 my @column_names = $obj->columns;
195
2053ab2a 196Returns all column names in the order they were declared to add_columns.
87f0da6a 197
198=cut
9c992ba1 199
200sub columns {
8e04bf91 201 my $self = shift;
aa1088bf 202 $self->throw_exception(
203 "columns() is a read-only accessor, did you mean add_columns()?"
204 ) if (@_ > 1);
701da8c4 205 return @{$self->{_ordered_columns}||[]};
571dced3 206}
207
87c4e602 208=head2 set_primary_key
209
27f01d1f 210=over 4
211
ebc77b53 212=item Arguments: @cols
27f01d1f 213
214=back
87f0da6a 215
9c992ba1 216Defines one or more columns as primary key for this source. Should be
217called after C<add_columns>.
87f0da6a 218
219Additionally, defines a unique constraint named C<primary>.
220
988bf309 221The primary key columns are used by L<DBIx::Class::PK::Auto> to
222retrieve automatically created values from the database.
223
87f0da6a 224=cut
9c992ba1 225
226sub set_primary_key {
227 my ($self, @cols) = @_;
228 # check if primary key columns are valid columns
8e04bf91 229 foreach my $col (@cols) {
230 $self->throw_exception("No such column $col on table " . $self->name)
231 unless $self->has_column($col);
9c992ba1 232 }
233 $self->_primaries(\@cols);
87f0da6a 234
235 $self->add_unique_constraint(primary => \@cols);
9c992ba1 236}
237
87f0da6a 238=head2 primary_columns
239
9c992ba1 240Read-only accessor which returns the list of primary keys.
30126ac7 241
87f0da6a 242=cut
9c992ba1 243
244sub primary_columns {
245 return @{shift->_primaries||[]};
246}
247
87f0da6a 248=head2 add_unique_constraint
249
250Declare a unique constraint on this source. Call once for each unique
988bf309 251constraint. Unique constraints are used when you call C<find> on a
2053ab2a 252L<DBIx::Class::ResultSet>. Only columns in the constraint are searched,
253for example:
27f01d1f 254
255 # For UNIQUE (column1, column2)
256 __PACKAGE__->add_unique_constraint(
257 constraint_name => [ qw/column1 column2/ ],
258 );
87f0da6a 259
260=cut
261
262sub add_unique_constraint {
263 my ($self, $name, $cols) = @_;
264
8e04bf91 265 foreach my $col (@$cols) {
266 $self->throw_exception("No such column $col on table " . $self->name)
267 unless $self->has_column($col);
87f0da6a 268 }
269
270 my %unique_constraints = $self->unique_constraints;
271 $unique_constraints{$name} = $cols;
272 $self->_unique_constraints(\%unique_constraints);
273}
274
275=head2 unique_constraints
276
277Read-only accessor which returns the list of unique constraints on this source.
278
279=cut
280
281sub unique_constraints {
282 return %{shift->_unique_constraints||{}};
283}
284
9c992ba1 285=head2 from
286
287Returns an expression of the source to be supplied to storage to specify
2053ab2a 288retrieval from this source. In the case of a database, the required FROM
289clause contents.
9c992ba1 290
291=cut
292
293=head2 storage
294
988bf309 295Returns the storage handle for the current schema.
296
297See also: L<DBIx::Class::Storage>
9c992ba1 298
299=cut
300
301sub storage { shift->schema->storage; }
302
8452e496 303=head2 add_relationship
304
305 $source->add_relationship('relname', 'related_source', $cond, $attrs);
306
24d67825 307The relationship name can be arbitrary, but must be unique for each
308relationship attached to this result source. 'related_source' should
309be the name with which the related result source was registered with
310the current schema. For example:
8452e496 311
24d67825 312 $schema->source('Book')->add_relationship('reviews', 'Review', {
313 'foreign.book_id' => 'self.id',
314 });
315
2053ab2a 316The condition C<$cond> needs to be an L<SQL::Abstract>-style
24d67825 317representation of the join between the tables. For example, if you're
318creating a rel from Author to Book,
988bf309 319
320 { 'foreign.author_id' => 'self.id' }
321
322will result in the JOIN clause
323
324 author me JOIN book foreign ON foreign.author_id = me.id
325
8452e496 326You can specify as many foreign => self mappings as necessary.
327
988bf309 328Valid attributes are as follows:
329
330=over 4
331
332=item join_type
333
334Explicitly specifies the type of join to use in the relationship. Any
335SQL join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in
336the SQL command immediately before C<JOIN>.
337
338=item proxy
339
24d67825 340An arrayref containing a list of accessors in the foreign class to proxy in
341the main class. If, for example, you do the following:
342
343 CD->might_have(liner_notes => 'LinerNotes', undef, {
344 proxy => [ qw/notes/ ],
345 });
346
347Then, assuming LinerNotes has an accessor named notes, you can do:
988bf309 348
24d67825 349 my $cd = CD->find(1);
2053ab2a 350 # set notes -- LinerNotes object is created if it doesn't exist
351 $cd->notes('Notes go here');
988bf309 352
353=item accessor
354
355Specifies the type of accessor that should be created for the
356relationship. Valid values are C<single> (for when there is only a single
357related object), C<multi> (when there can be many), and C<filter> (for
358when there is a single related object, but you also want the relationship
359accessor to double as a column accessor). For C<multi> accessors, an
360add_to_* method is also created, which calls C<create_related> for the
361relationship.
362
8452e496 363=back
364
365=cut
366
367sub add_relationship {
368 my ($self, $rel, $f_source_name, $cond, $attrs) = @_;
27f01d1f 369 $self->throw_exception("Can't create relationship without join condition")
370 unless $cond;
8452e496 371 $attrs ||= {};
87772e46 372
8452e496 373 my %rels = %{ $self->_relationships };
374 $rels{$rel} = { class => $f_source_name,
87772e46 375 source => $f_source_name,
8452e496 376 cond => $cond,
377 attrs => $attrs };
378 $self->_relationships(\%rels);
379
30126ac7 380 return $self;
87772e46 381
953a18ef 382 # XXX disabled. doesn't work properly currently. skip in tests.
383
8452e496 384 my $f_source = $self->schema->source($f_source_name);
385 unless ($f_source) {
386 eval "require $f_source_name;";
387 if ($@) {
388 die $@ unless $@ =~ /Can't locate/;
389 }
390 $f_source = $f_source_name->result_source;
87772e46 391 #my $s_class = ref($self->schema);
392 #$f_source_name =~ m/^${s_class}::(.*)$/;
393 #$self->schema->register_class(($1 || $f_source_name), $f_source_name);
394 #$f_source = $self->schema->source($f_source_name);
8452e496 395 }
396 return unless $f_source; # Can't test rel without f_source
397
398 eval { $self->resolve_join($rel, 'me') };
399
400 if ($@) { # If the resolve failed, back out and re-throw the error
401 delete $rels{$rel}; #
402 $self->_relationships(\%rels);
701da8c4 403 $self->throw_exception("Error creating relationship $rel: $@");
8452e496 404 }
405 1;
406}
407
87c4e602 408=head2 relationships
8452e496 409
2053ab2a 410Returns all relationship names for this source.
8452e496 411
412=cut
413
414sub relationships {
415 return keys %{shift->_relationships};
416}
417
87c4e602 418=head2 relationship_info
419
27f01d1f 420=over 4
421
ebc77b53 422=item Arguments: $relname
27f01d1f 423
424=back
8452e496 425
2053ab2a 426Returns a hash of relationship information for the specified relationship
427name.
8452e496 428
429=cut
430
431sub relationship_info {
432 my ($self, $rel) = @_;
433 return $self->_relationships->{$rel};
434}
435
87c4e602 436=head2 has_relationship
437
27f01d1f 438=over 4
439
ebc77b53 440=item Arguments: $rel
27f01d1f 441
442=back
953a18ef 443
2053ab2a 444Returns true if the source has a relationship of this name, false otherwise.
988bf309 445
446=cut
953a18ef 447
448sub has_relationship {
449 my ($self, $rel) = @_;
450 return exists $self->_relationships->{$rel};
451}
452
87c4e602 453=head2 resolve_join
454
27f01d1f 455=over 4
456
ebc77b53 457=item Arguments: $relation
27f01d1f 458
459=back
8452e496 460
2053ab2a 461Returns the join structure required for the related result source.
8452e496 462
463=cut
464
465sub resolve_join {
489709af 466 my ($self, $join, $alias, $seen) = @_;
467 $seen ||= {};
87772e46 468 if (ref $join eq 'ARRAY') {
489709af 469 return map { $self->resolve_join($_, $alias, $seen) } @$join;
87772e46 470 } elsif (ref $join eq 'HASH') {
489709af 471 return
887ce227 472 map {
473 my $as = ($seen->{$_} ? $_.'_'.($seen->{$_}+1) : $_);
474 ($self->resolve_join($_, $alias, $seen),
475 $self->related_source($_)->resolve_join($join->{$_}, $as, $seen));
476 } keys %$join;
87772e46 477 } elsif (ref $join) {
701da8c4 478 $self->throw_exception("No idea how to resolve join reftype ".ref $join);
87772e46 479 } else {
489709af 480 my $count = ++$seen->{$join};
481 #use Data::Dumper; warn Dumper($seen);
482 my $as = ($count > 1 ? "${join}_${count}" : $join);
3842b955 483 my $rel_info = $self->relationship_info($join);
701da8c4 484 $self->throw_exception("No such relationship ${join}") unless $rel_info;
3842b955 485 my $type = $rel_info->{attrs}{join_type} || '';
489709af 486 return [ { $as => $self->related_source($join)->from,
953a18ef 487 -join_type => $type },
489709af 488 $self->resolve_condition($rel_info->{cond}, $as, $alias) ];
953a18ef 489 }
490}
491
87c4e602 492=head2 resolve_condition
493
27f01d1f 494=over 4
495
ebc77b53 496=item Arguments: $cond, $as, $alias|$object
27f01d1f 497
498=back
953a18ef 499
3842b955 500Resolves the passed condition to a concrete query fragment. If given an alias,
953a18ef 501returns a join condition; if given an object, inverts that object to produce
502a related conditional from that object.
503
504=cut
505
506sub resolve_condition {
489709af 507 my ($self, $cond, $as, $for) = @_;
953a18ef 508 #warn %$cond;
509 if (ref $cond eq 'HASH') {
510 my %ret;
511 while (my ($k, $v) = each %{$cond}) {
512 # XXX should probably check these are valid columns
27f01d1f 513 $k =~ s/^foreign\.// ||
514 $self->throw_exception("Invalid rel cond key ${k}");
515 $v =~ s/^self\.// ||
516 $self->throw_exception("Invalid rel cond val ${v}");
953a18ef 517 if (ref $for) { # Object
3842b955 518 #warn "$self $k $for $v";
519 $ret{$k} = $for->get_column($v);
520 #warn %ret;
fde6e28e 521 } elsif (ref $as) { # reverse object
522 $ret{$v} = $as->get_column($k);
953a18ef 523 } else {
489709af 524 $ret{"${as}.${k}"} = "${for}.${v}";
953a18ef 525 }
953a18ef 526 }
527 return \%ret;
5efe4c79 528 } elsif (ref $cond eq 'ARRAY') {
489709af 529 return [ map { $self->resolve_condition($_, $as, $for) } @$cond ];
953a18ef 530 } else {
531 die("Can't handle this yet :(");
87772e46 532 }
533}
534
87c4e602 535=head2 resolve_prefetch
536
27f01d1f 537=over 4
538
ebc77b53 539=item Arguments: hashref/arrayref/scalar
27f01d1f 540
541=back
988bf309 542
b3e8ac9b 543Accepts one or more relationships for the current source and returns an
544array of column names for each of those relationships. Column names are
545prefixed relative to the current source, in accordance with where they appear
546in the supplied relationships. Examples:
547
5ac6a044 548 my $source = $schema->resultset('Tag')->source;
b3e8ac9b 549 @columns = $source->resolve_prefetch( { cd => 'artist' } );
550
551 # @columns =
552 #(
553 # 'cd.cdid',
554 # 'cd.artist',
555 # 'cd.title',
556 # 'cd.year',
557 # 'cd.artist.artistid',
558 # 'cd.artist.name'
559 #)
560
561 @columns = $source->resolve_prefetch( qw[/ cd /] );
562
563 # @columns =
564 #(
565 # 'cd.cdid',
566 # 'cd.artist',
567 # 'cd.title',
568 # 'cd.year'
569 #)
570
571 $source = $schema->resultset('CD')->source;
572 @columns = $source->resolve_prefetch( qw[/ artist producer /] );
573
574 # @columns =
575 #(
576 # 'artist.artistid',
577 # 'artist.name',
578 # 'producer.producerid',
579 # 'producer.name'
580 #)
988bf309 581
b3e8ac9b 582=cut
583
584sub resolve_prefetch {
0f66a01b 585 my ($self, $pre, $alias, $seen, $order, $collapse) = @_;
489709af 586 $seen ||= {};
b3e8ac9b 587 #$alias ||= $self->name;
588 #warn $alias, Dumper $pre;
589 if( ref $pre eq 'ARRAY' ) {
0f66a01b 590 return
591 map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) }
592 @$pre;
b3e8ac9b 593 }
594 elsif( ref $pre eq 'HASH' ) {
595 my @ret =
596 map {
0f66a01b 597 $self->resolve_prefetch($_, $alias, $seen, $order, $collapse),
489709af 598 $self->related_source($_)->resolve_prefetch(
0f66a01b 599 $pre->{$_}, "${alias}.$_", $seen, $order, $collapse)
600 } keys %$pre;
b3e8ac9b 601 #die Dumper \@ret;
602 return @ret;
603 }
604 elsif( ref $pre ) {
a86b1efe 605 $self->throw_exception(
606 "don't know how to resolve prefetch reftype ".ref($pre));
b3e8ac9b 607 }
608 else {
489709af 609 my $count = ++$seen->{$pre};
610 my $as = ($count > 1 ? "${pre}_${count}" : $pre);
b3e8ac9b 611 my $rel_info = $self->relationship_info( $pre );
a86b1efe 612 $self->throw_exception( $self->name . " has no such relationship '$pre'" )
613 unless $rel_info;
37f23589 614 my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
a86b1efe 615 my $rel_source = $self->related_source($pre);
0f66a01b 616
617 if (exists $rel_info->{attrs}{accessor}
618 && $rel_info->{attrs}{accessor} eq 'multi') {
619 $self->throw_exception(
620 "Can't prefetch has_many ${pre} (join cond too complex)")
621 unless ref($rel_info->{cond}) eq 'HASH';
37f23589 622 my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
0f66a01b 623 keys %{$rel_info->{cond}};
624 $collapse->{"${as_prefix}${pre}"} = \@key;
5a5bec6c 625 my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
626 ? @{$rel_info->{attrs}{order_by}}
627 : (defined $rel_info->{attrs}{order_by}
628 ? ($rel_info->{attrs}{order_by})
629 : ()));
630 push(@$order, map { "${as}.$_" } (@key, @ord));
0f66a01b 631 }
632
489709af 633 return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
a86b1efe 634 $rel_source->columns;
b3e8ac9b 635 #warn $alias, Dumper (\@ret);
489709af 636 #return @ret;
b3e8ac9b 637 }
638}
953a18ef 639
87c4e602 640=head2 related_source
641
27f01d1f 642=over 4
643
ebc77b53 644=item Arguments: $relname
27f01d1f 645
646=back
87772e46 647
2053ab2a 648Returns the result source object for the given relationship.
87772e46 649
650=cut
651
652sub related_source {
653 my ($self, $rel) = @_;
aea52c85 654 if( !$self->has_relationship( $rel ) ) {
701da8c4 655 $self->throw_exception("No such relationship '$rel'");
aea52c85 656 }
87772e46 657 return $self->schema->source($self->relationship_info($rel)->{source});
8452e496 658}
659
77254782 660=head2 related_class
661
27f01d1f 662=over 4
663
ebc77b53 664=item Arguments: $relname
27f01d1f 665
666=back
77254782 667
2053ab2a 668Returns the class name for objects in the given relationship.
77254782 669
670=cut
671
672sub related_class {
673 my ($self, $rel) = @_;
674 if( !$self->has_relationship( $rel ) ) {
675 $self->throw_exception("No such relationship '$rel'");
676 }
677 return $self->schema->class($self->relationship_info($rel)->{source});
678}
679
5ac6a044 680=head2 resultset
681
bcc5a210 682Returns a resultset for the given source. This will initially be created
683on demand by calling
5ac6a044 684
988bf309 685 $self->resultset_class->new($self, $self->resultset_attributes)
5ac6a044 686
bcc5a210 687but is cached from then on unless resultset_class changes.
688
5ac6a044 689=head2 resultset_class
690
988bf309 691Set the class of the resultset, this is useful if you want to create your
692own resultset methods. Create your own class derived from
693L<DBIx::Class::ResultSet>, and set it here.
5ac6a044 694
695=head2 resultset_attributes
696
988bf309 697Specify here any attributes you wish to pass to your specialised resultset.
5ac6a044 698
699=cut
700
701sub resultset {
702 my $self = shift;
27f01d1f 703 $self->throw_exception(
704 'resultset does not take any arguments. If you want another resultset, '.
705 'call it on the schema instead.'
706 ) if scalar @_;
707 return $self->{_resultset}
708 if ref $self->{_resultset} eq $self->resultset_class;
709 return $self->{_resultset} = $self->resultset_class->new(
710 $self, $self->{resultset_attributes}
711 );
5ac6a044 712}
713
701da8c4 714=head2 throw_exception
715
2053ab2a 716See L<DBIx::Class::Schema/"throw_exception">.
701da8c4 717
718=cut
719
720sub throw_exception {
721 my $self = shift;
722 if (defined $self->schema) {
723 $self->schema->throw_exception(@_);
724 } else {
725 croak(@_);
726 }
727}
728
9c992ba1 729=head1 AUTHORS
730
731Matt S. Trout <mst@shadowcatsystems.co.uk>
732
733=head1 LICENSE
734
735You may distribute this code under the same terms as Perl itself.
736
737=cut
738