Merge 'find_changes' into 'DBIx-Class-current'
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSource.pm
1 package DBIx::Class::ResultSource;
2
3 use strict;
4 use warnings;
5
6 use DBIx::Class::ResultSet;
7 use Carp::Clan qw/^DBIx::Class/;
8 use Storable;
9
10 use base qw/DBIx::Class/;
11 __PACKAGE__->load_components(qw/AccessorGroup/);
12
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 source_name/);
19
20 =head1 NAME
21
22 DBIx::Class::ResultSource - Result source object
23
24 =head1 SYNOPSIS
25
26 =head1 DESCRIPTION
27
28 A ResultSource is a component of a schema from which results can be directly
29 retrieved, most usually a table (see L<DBIx::Class::ResultSource::Table>)
30
31 =head1 METHODS
32
33 =cut
34
35 sub new {
36   my ($class, $attrs) = @_;
37   $class = ref $class if ref $class;
38   my $new = bless({ %{$attrs || {}}, _resultset => undef }, $class);
39   $new->{resultset_class} ||= 'DBIx::Class::ResultSet';
40   $new->{resultset_attributes} = { %{$new->{resultset_attributes} || {}} };
41   $new->{_ordered_columns} = [ @{$new->{_ordered_columns}||[]}];
42   $new->{_columns} = { %{$new->{_columns}||{}} };
43   $new->{_relationships} = { %{$new->{_relationships}||{}} };
44   $new->{name} ||= "!!NAME NOT SET!!";
45   $new->{_columns_info_loaded} ||= 0;
46   return $new;
47 }
48
49 =pod
50
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
57 Adds columns to the result source. If supplied key => hashref pairs, uses
58 the hashref as the column_info for that column. Repeated calls of this
59 method will add more columns, not replace them.
60
61 The contents of the column_info are not set in stone. The following
62 keys are currently recognised/used by DBIx::Class:
63
64 =over 4
65
66 =item accessor
67
68 Use this to set the name of the accessor for this column. If unset,
69 the name of the column will be used.
70
71 =item data_type
72
73 This contains the column type. It is automatically filled by the
74 L<SQL::Translator::Producer::DBIx::Class::File> producer, and the
75 L<DBIx::Class::Schema::Loader> module. If you do not enter a
76 data_type, DBIx::Class will attempt to retrieve it from the
77 database for you, using L<DBI>'s column_info method. The values of this
78 key are typically upper-cased.
79
80 Currently there is no standard set of values for the data_type. Use
81 whatever your database supports.
82
83 =item size
84
85 The length of your column, if it is a column type that can have a size
86 restriction. This is currently not used by DBIx::Class.
87
88 =item is_nullable
89
90 Set this to a true value for a columns that is allowed to contain
91 NULL values. This is currently not used by DBIx::Class.
92
93 =item is_auto_increment
94
95 Set this to a true value for a column whose value is somehow
96 automatically set. This is used to determine which columns to empty
97 when cloning objects using C<copy>.
98
99 =item is_foreign_key
100
101 Set this to a true value for a column that contains a key from a
102 foreign table. This is currently not used by DBIx::Class.
103
104 =item default_value
105
106 Set this to the default value which will be inserted into a column
107 by the database. Can contain either a value or a function. This is
108 currently not used by DBIx::Class.
109
110 =item sequence
111
112 Set this on a primary key column to the name of the sequence used to
113 generate a new key value. If not specified, L<DBIx::Class::PK::Auto>
114 will attempt to retrieve the name of the sequence from the database
115 automatically.
116
117 =back
118
119 =head2 add_column
120
121   $table->add_column('col' => \%info?);
122
123 Convenience alias to add_columns.
124
125 =cut
126
127 sub add_columns {
128   my ($self, @cols) = @_;
129   $self->_ordered_columns(\@cols) unless $self->_ordered_columns;
130
131   my @added;
132   my $columns = $self->_columns;
133   while (my $col = shift @cols) {
134     # If next entry is { ... } use that for the column info, if not
135     # use an empty hashref
136     my $column_info = ref $cols[0] ? shift(@cols) : {};
137     push(@added, $col) unless exists $columns->{$col};
138     $columns->{$col} = $column_info;
139   }
140   push @{ $self->_ordered_columns }, @added;
141   return $self;
142 }
143
144 *add_column = \&add_columns;
145
146 =head2 has_column
147
148   if ($obj->has_column($col)) { ... }
149
150 Returns true if the source has a column of this name, false otherwise.
151
152 =cut
153
154 sub has_column {
155   my ($self, $column) = @_;
156   return exists $self->_columns->{$column};
157 }
158
159 =head2 column_info
160
161   my $info = $obj->column_info($col);
162
163 Returns the column metadata hashref for a column. See the description
164 of add_column for information on the contents of the hashref.
165
166 =cut
167
168 sub column_info {
169   my ($self, $column) = @_;
170   $self->throw_exception("No such column $column")
171     unless exists $self->_columns->{$column};
172   #warn $self->{_columns_info_loaded}, "\n";
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         }
186       }
187     }
188   }
189   return $self->_columns->{$column};
190 }
191
192 =head2 columns
193
194   my @column_names = $obj->columns;
195
196 Returns all column names in the order they were declared to add_columns.
197
198 =cut
199
200 sub columns {
201   my $self = shift;
202   $self->throw_exception(
203     "columns() is a read-only accessor, did you mean add_columns()?"
204   ) if (@_ > 1);
205   return @{$self->{_ordered_columns}||[]};
206 }
207
208 =head2 remove_columns
209
210   $table->remove_columns(qw/col1 col2 col3/);
211
212 Removes columns from the result source.
213
214 =head2 remove_column
215
216   $table->remove_column('col');
217
218 Convenience alias to remove_columns.
219
220 =cut
221
222 sub remove_columns {
223   my ($self, @cols) = @_;
224
225   return unless $self->_ordered_columns;
226
227   my $columns = $self->_columns;
228   my @remaining;
229
230   foreach my $col (@{$self->_ordered_columns}) {
231     push @remaining, $col unless grep(/$col/, @cols);
232   }
233
234   foreach (@cols) {
235     undef $columns->{$_};
236   };
237
238   $self->_ordered_columns(\@remaining);
239 }
240
241 *remove_column = \&remove_columns;
242
243 =head2 set_primary_key
244
245 =over 4
246
247 =item Arguments: @cols
248
249 =back
250
251 Defines one or more columns as primary key for this source. Should be
252 called after C<add_columns>.
253
254 Additionally, defines a unique constraint named C<primary>.
255
256 The primary key columns are used by L<DBIx::Class::PK::Auto> to
257 retrieve automatically created values from the database.
258
259 =cut
260
261 sub set_primary_key {
262   my ($self, @cols) = @_;
263   # check if primary key columns are valid columns
264   foreach my $col (@cols) {
265     $self->throw_exception("No such column $col on table " . $self->name)
266       unless $self->has_column($col);
267   }
268   $self->_primaries(\@cols);
269
270   $self->add_unique_constraint(primary => \@cols);
271 }
272
273 =head2 primary_columns
274
275 Read-only accessor which returns the list of primary keys.
276
277 =cut
278
279 sub primary_columns {
280   return @{shift->_primaries||[]};
281 }
282
283 =head2 add_unique_constraint
284
285 Declare a unique constraint on this source. Call once for each unique
286 constraint.
287
288   # For UNIQUE (column1, column2)
289   __PACKAGE__->add_unique_constraint(
290     constraint_name => [ qw/column1 column2/ ],
291   );
292
293 Unique constraints are used, for example, when you call
294 L<DBIx::Class::ResultSet/find>. Only columns in the constraint are searched.
295
296 =cut
297
298 sub add_unique_constraint {
299   my ($self, $name, $cols) = @_;
300
301   foreach my $col (@$cols) {
302     $self->throw_exception("No such column $col on table " . $self->name)
303       unless $self->has_column($col);
304   }
305
306   my %unique_constraints = $self->unique_constraints;
307   $unique_constraints{$name} = $cols;
308   $self->_unique_constraints(\%unique_constraints);
309 }
310
311 =head2 unique_constraints
312
313 Read-only accessor which returns the list of unique constraints on this source.
314
315 =cut
316
317 sub unique_constraints {
318   return %{shift->_unique_constraints||{}};
319 }
320
321 =head2 unique_constraint_names
322
323 Returns the list of unique constraint names defined on this source.
324
325 =cut
326
327 sub unique_constraint_names {
328   my ($self) = @_;
329
330   my %unique_constraints = $self->unique_constraints;
331
332   return keys %unique_constraints;
333 }
334
335 =head2 unique_constraint_columns
336
337 Returns the list of columns that make up the specified unique constraint.
338
339 =cut
340
341 sub unique_constraint_columns {
342   my ($self, $constraint_name) = @_;
343
344   my %unique_constraints = $self->unique_constraints;
345
346   $self->throw_exception(
347     "Unknown unique constraint $constraint_name on '" . $self->name . "'"
348   ) unless exists $unique_constraints{$constraint_name};
349
350   return @{ $unique_constraints{$constraint_name} };
351 }
352
353 =head2 from
354
355 Returns an expression of the source to be supplied to storage to specify
356 retrieval from this source. In the case of a database, the required FROM
357 clause contents.
358
359 =cut
360
361 =head2 storage
362
363 Returns the storage handle for the current schema.
364
365 See also: L<DBIx::Class::Storage>
366
367 =cut
368
369 sub storage { shift->schema->storage; }
370
371 =head2 add_relationship
372
373   $source->add_relationship('relname', 'related_source', $cond, $attrs);
374
375 The relationship name can be arbitrary, but must be unique for each
376 relationship attached to this result source. 'related_source' should
377 be the name with which the related result source was registered with
378 the current schema. For example:
379
380   $schema->source('Book')->add_relationship('reviews', 'Review', {
381     'foreign.book_id' => 'self.id',
382   });
383
384 The condition C<$cond> needs to be an L<SQL::Abstract>-style
385 representation of the join between the tables. For example, if you're
386 creating a rel from Author to Book,
387
388   { 'foreign.author_id' => 'self.id' }
389
390 will result in the JOIN clause
391
392   author me JOIN book foreign ON foreign.author_id = me.id
393
394 You can specify as many foreign => self mappings as necessary.
395
396 Valid attributes are as follows:
397
398 =over 4
399
400 =item join_type
401
402 Explicitly specifies the type of join to use in the relationship. Any
403 SQL join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in
404 the SQL command immediately before C<JOIN>.
405
406 =item proxy
407
408 An arrayref containing a list of accessors in the foreign class to proxy in
409 the main class. If, for example, you do the following:
410
411   CD->might_have(liner_notes => 'LinerNotes', undef, {
412     proxy => [ qw/notes/ ],
413   });
414
415 Then, assuming LinerNotes has an accessor named notes, you can do:
416
417   my $cd = CD->find(1);
418   # set notes -- LinerNotes object is created if it doesn't exist
419   $cd->notes('Notes go here');
420
421 =item accessor
422
423 Specifies the type of accessor that should be created for the
424 relationship. Valid values are C<single> (for when there is only a single
425 related object), C<multi> (when there can be many), and C<filter> (for
426 when there is a single related object, but you also want the relationship
427 accessor to double as a column accessor). For C<multi> accessors, an
428 add_to_* method is also created, which calls C<create_related> for the
429 relationship.
430
431 =back
432
433 =cut
434
435 sub add_relationship {
436   my ($self, $rel, $f_source_name, $cond, $attrs) = @_;
437   $self->throw_exception("Can't create relationship without join condition")
438     unless $cond;
439   $attrs ||= {};
440
441   my %rels = %{ $self->_relationships };
442   $rels{$rel} = { class => $f_source_name,
443                   source => $f_source_name,
444                   cond  => $cond,
445                   attrs => $attrs };
446   $self->_relationships(\%rels);
447
448   return $self;
449
450   # XXX disabled. doesn't work properly currently. skip in tests.
451
452   my $f_source = $self->schema->source($f_source_name);
453   unless ($f_source) {
454     eval "require $f_source_name;";
455     if ($@) {
456       die $@ unless $@ =~ /Can't locate/;
457     }
458     $f_source = $f_source_name->result_source;
459     #my $s_class = ref($self->schema);
460     #$f_source_name =~ m/^${s_class}::(.*)$/;
461     #$self->schema->register_class(($1 || $f_source_name), $f_source_name);
462     #$f_source = $self->schema->source($f_source_name);
463   }
464   return unless $f_source; # Can't test rel without f_source
465
466   eval { $self->resolve_join($rel, 'me') };
467
468   if ($@) { # If the resolve failed, back out and re-throw the error
469     delete $rels{$rel}; #
470     $self->_relationships(\%rels);
471     $self->throw_exception("Error creating relationship $rel: $@");
472   }
473   1;
474 }
475
476 =head2 relationships
477
478 Returns all relationship names for this source.
479
480 =cut
481
482 sub relationships {
483   return keys %{shift->_relationships};
484 }
485
486 =head2 relationship_info
487
488 =over 4
489
490 =item Arguments: $relname
491
492 =back
493
494 Returns a hash of relationship information for the specified relationship
495 name.
496
497 =cut
498
499 sub relationship_info {
500   my ($self, $rel) = @_;
501   return $self->_relationships->{$rel};
502 }
503
504 =head2 has_relationship
505
506 =over 4
507
508 =item Arguments: $rel
509
510 =back
511
512 Returns true if the source has a relationship of this name, false otherwise.
513
514 =cut
515
516 sub has_relationship {
517   my ($self, $rel) = @_;
518   return exists $self->_relationships->{$rel};
519 }
520
521 =head2 reverse_relationship_info
522
523 =over 4
524
525 =item Arguments: $relname
526
527 =back
528
529 Returns an array of hash references of relationship information for
530 the other side of the specified relationship name.
531
532 =cut
533
534 sub reverse_relationship_info {
535   my ($self, $rel) = @_;
536   my $rel_info = $self->relationship_info($rel);
537   my $ret = {};
538
539   return $ret unless ((ref $rel_info->{cond}) eq 'HASH');
540
541   my @cond = keys(%{$rel_info->{cond}});
542   my @refkeys = map {/^\w+\.(\w+)$/} @cond;
543   my @keys = map {$rel_info->{cond}->{$_} =~ /^\w+\.(\w+)$/} @cond;
544
545   # Get the related result source for this relationship
546   my $othertable = $self->related_source($rel);
547
548   # Get all the relationships for that source that related to this source
549   # whose foreign column set are our self columns on $rel and whose self
550   # columns are our foreign columns on $rel.
551   my @otherrels = $othertable->relationships();
552   my $otherrelationship;
553   foreach my $otherrel (@otherrels) {
554     my $otherrel_info = $othertable->relationship_info($otherrel);
555
556     my $back = $othertable->related_source($otherrel);
557     next unless $back->name eq $self->name;
558
559     my @othertestconds;
560
561     if (ref $otherrel_info->{cond} eq 'HASH') {
562       @othertestconds = ($otherrel_info->{cond});
563     }
564     elsif (ref $otherrel_info->{cond} eq 'ARRAY') {
565       @othertestconds = @{$otherrel_info->{cond}};
566     }
567     else {
568       next;
569     }
570
571     foreach my $othercond (@othertestconds) {
572       my @other_cond = keys(%$othercond);
573       my @other_refkeys = map {/^\w+\.(\w+)$/} @other_cond;
574       my @other_keys = map {$othercond->{$_} =~ /^\w+\.(\w+)$/} @other_cond;
575       next if (!$self->compare_relationship_keys(\@refkeys, \@other_keys) ||
576                !$self->compare_relationship_keys(\@other_refkeys, \@keys));
577       $ret->{$otherrel} =  $otherrel_info;
578     }
579   }
580   return $ret;
581 }
582
583 =head2 compare_relationship_keys
584
585 =over 4
586
587 =item Arguments: $keys1, $keys2
588
589 =back
590
591 Returns true if both sets of keynames are the same, false otherwise.
592
593 =cut
594
595 sub compare_relationship_keys {
596   my ($self, $keys1, $keys2) = @_;
597
598   # Make sure every keys1 is in keys2
599   my $found;
600   foreach my $key (@$keys1) {
601     $found = 0;
602     foreach my $prim (@$keys2) {
603       if ($prim eq $key) {
604         $found = 1;
605         last;
606       }
607     }
608     last unless $found;
609   }
610
611   # Make sure every key2 is in key1
612   if ($found) {
613     foreach my $prim (@$keys2) {
614       $found = 0;
615       foreach my $key (@$keys1) {
616         if ($prim eq $key) {
617           $found = 1;
618           last;
619         }
620       }
621       last unless $found;
622     }
623   }
624
625   return $found;
626 }
627
628 =head2 resolve_join
629
630 =over 4
631
632 =item Arguments: $relation
633
634 =back
635
636 Returns the join structure required for the related result source.
637
638 =cut
639
640 sub resolve_join {
641   my ($self, $join, $alias, $seen) = @_;
642   $seen ||= {};
643   if (ref $join eq 'ARRAY') {
644     return map { $self->resolve_join($_, $alias, $seen) } @$join;
645   } elsif (ref $join eq 'HASH') {
646     return
647       map {
648         my $as = ($seen->{$_} ? $_.'_'.($seen->{$_}+1) : $_);
649         ($self->resolve_join($_, $alias, $seen),
650           $self->related_source($_)->resolve_join($join->{$_}, $as, $seen));
651       } keys %$join;
652   } elsif (ref $join) {
653     $self->throw_exception("No idea how to resolve join reftype ".ref $join);
654   } else {
655     my $count = ++$seen->{$join};
656     #use Data::Dumper; warn Dumper($seen);
657     my $as = ($count > 1 ? "${join}_${count}" : $join);
658     my $rel_info = $self->relationship_info($join);
659     $self->throw_exception("No such relationship ${join}") unless $rel_info;
660     my $type = $rel_info->{attrs}{join_type} || '';
661     return [ { $as => $self->related_source($join)->from,
662                -join_type => $type },
663              $self->resolve_condition($rel_info->{cond}, $as, $alias) ];
664   }
665 }
666
667 =head2 resolve_condition
668
669 =over 4
670
671 =item Arguments: $cond, $as, $alias|$object
672
673 =back
674
675 Resolves the passed condition to a concrete query fragment. If given an alias,
676 returns a join condition; if given an object, inverts that object to produce
677 a related conditional from that object.
678
679 =cut
680
681 sub resolve_condition {
682   my ($self, $cond, $as, $for) = @_;
683   #warn %$cond;
684   if (ref $cond eq 'HASH') {
685     my %ret;
686     while (my ($k, $v) = each %{$cond}) {
687       # XXX should probably check these are valid columns
688       $k =~ s/^foreign\.// ||
689         $self->throw_exception("Invalid rel cond key ${k}");
690       $v =~ s/^self\.// ||
691         $self->throw_exception("Invalid rel cond val ${v}");
692       if (ref $for) { # Object
693         #warn "$self $k $for $v";
694         $ret{$k} = $for->get_column($v);
695         #warn %ret;
696       } elsif (ref $as) { # reverse object
697         $ret{$v} = $as->get_column($k);
698       } else {
699         $ret{"${as}.${k}"} = "${for}.${v}";
700       }
701     }
702     return \%ret;
703   } elsif (ref $cond eq 'ARRAY') {
704     return [ map { $self->resolve_condition($_, $as, $for) } @$cond ];
705   } else {
706    die("Can't handle this yet :(");
707   }
708 }
709
710 =head2 resolve_prefetch
711
712 =over 4
713
714 =item Arguments: hashref/arrayref/scalar
715
716 =back
717
718 Accepts one or more relationships for the current source and returns an
719 array of column names for each of those relationships. Column names are
720 prefixed relative to the current source, in accordance with where they appear
721 in the supplied relationships. Examples:
722
723   my $source = $schema->resultset('Tag')->source;
724   @columns = $source->resolve_prefetch( { cd => 'artist' } );
725
726   # @columns =
727   #(
728   #  'cd.cdid',
729   #  'cd.artist',
730   #  'cd.title',
731   #  'cd.year',
732   #  'cd.artist.artistid',
733   #  'cd.artist.name'
734   #)
735
736   @columns = $source->resolve_prefetch( qw[/ cd /] );
737
738   # @columns =
739   #(
740   #   'cd.cdid',
741   #   'cd.artist',
742   #   'cd.title',
743   #   'cd.year'
744   #)
745
746   $source = $schema->resultset('CD')->source;
747   @columns = $source->resolve_prefetch( qw[/ artist producer /] );
748
749   # @columns =
750   #(
751   #  'artist.artistid',
752   #  'artist.name',
753   #  'producer.producerid',
754   #  'producer.name'
755   #)
756
757 =cut
758
759 sub resolve_prefetch {
760   my ($self, $pre, $alias, $seen, $order, $collapse) = @_;
761   $seen ||= {};
762   #$alias ||= $self->name;
763   #warn $alias, Dumper $pre;
764   if( ref $pre eq 'ARRAY' ) {
765     return
766       map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) }
767         @$pre;
768   }
769   elsif( ref $pre eq 'HASH' ) {
770     my @ret =
771     map {
772       $self->resolve_prefetch($_, $alias, $seen, $order, $collapse),
773       $self->related_source($_)->resolve_prefetch(
774                $pre->{$_}, "${alias}.$_", $seen, $order, $collapse)
775     } keys %$pre;
776     #die Dumper \@ret;
777     return @ret;
778   }
779   elsif( ref $pre ) {
780     $self->throw_exception(
781       "don't know how to resolve prefetch reftype ".ref($pre));
782   }
783   else {
784     my $count = ++$seen->{$pre};
785     my $as = ($count > 1 ? "${pre}_${count}" : $pre);
786     my $rel_info = $self->relationship_info( $pre );
787     $self->throw_exception( $self->name . " has no such relationship '$pre'" )
788       unless $rel_info;
789     my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
790     my $rel_source = $self->related_source($pre);
791
792     if (exists $rel_info->{attrs}{accessor}
793          && $rel_info->{attrs}{accessor} eq 'multi') {
794       $self->throw_exception(
795         "Can't prefetch has_many ${pre} (join cond too complex)")
796         unless ref($rel_info->{cond}) eq 'HASH';
797       my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
798                     keys %{$rel_info->{cond}};
799       $collapse->{"${as_prefix}${pre}"} = \@key;
800       my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
801                    ? @{$rel_info->{attrs}{order_by}}
802                    : (defined $rel_info->{attrs}{order_by}
803                        ? ($rel_info->{attrs}{order_by})
804                        : ()));
805       push(@$order, map { "${as}.$_" } (@key, @ord));
806     }
807
808     return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
809       $rel_source->columns;
810     #warn $alias, Dumper (\@ret);
811     #return @ret;
812   }
813 }
814
815 =head2 related_source
816
817 =over 4
818
819 =item Arguments: $relname
820
821 =back
822
823 Returns the result source object for the given relationship.
824
825 =cut
826
827 sub related_source {
828   my ($self, $rel) = @_;
829   if( !$self->has_relationship( $rel ) ) {
830     $self->throw_exception("No such relationship '$rel'");
831   }
832   return $self->schema->source($self->relationship_info($rel)->{source});
833 }
834
835 =head2 related_class
836
837 =over 4
838
839 =item Arguments: $relname
840
841 =back
842
843 Returns the class name for objects in the given relationship.
844
845 =cut
846
847 sub related_class {
848   my ($self, $rel) = @_;
849   if( !$self->has_relationship( $rel ) ) {
850     $self->throw_exception("No such relationship '$rel'");
851   }
852   return $self->schema->class($self->relationship_info($rel)->{source});
853 }
854
855 =head2 resultset
856
857 Returns a resultset for the given source. This will initially be created
858 on demand by calling
859
860   $self->resultset_class->new($self, $self->resultset_attributes)
861
862 but is cached from then on unless resultset_class changes.
863
864 =head2 resultset_class
865
866 Set the class of the resultset, this is useful if you want to create your
867 own resultset methods. Create your own class derived from
868 L<DBIx::Class::ResultSet>, and set it here.
869
870 =head2 resultset_attributes
871
872 Specify here any attributes you wish to pass to your specialised resultset.
873
874 =cut
875
876 sub resultset {
877   my $self = shift;
878   $self->throw_exception(
879     'resultset does not take any arguments. If you want another resultset, '.
880     'call it on the schema instead.'
881   ) if scalar @_;
882
883   # disabled until we can figure out a way to do it without consistency issues
884   #
885   #return $self->{_resultset}
886   #  if ref $self->{_resultset} eq $self->resultset_class;
887   #return $self->{_resultset} =
888
889   return $self->resultset_class->new(
890     $self, $self->{resultset_attributes}
891   );
892 }
893
894 =head2 source_name
895
896 =over 4
897
898 =item Arguments: $source_name
899
900 =back
901
902 Set the name of the result source when it is loaded into a schema.
903 This is usefull if you want to refer to a result source by a name other than
904 its class name.
905
906   package ArchivedBooks;
907   use base qw/DBIx::Class/;
908   __PACKAGE__->table('books_archive');
909   __PACKAGE__->source_name('Books');
910
911   # from your schema...
912   $schema->resultset('Books')->find(1);
913
914 =head2 throw_exception
915
916 See L<DBIx::Class::Schema/"throw_exception">.
917
918 =cut
919
920 sub throw_exception {
921   my $self = shift;
922   if (defined $self->schema) {
923     $self->schema->throw_exception(@_);
924   } else {
925     croak(@_);
926   }
927 }
928
929 =head1 AUTHORS
930
931 Matt S. Trout <mst@shadowcatsystems.co.uk>
932
933 =head1 LICENSE
934
935 You may distribute this code under the same terms as Perl itself.
936
937 =cut
938