Move ordered tests from 26 to 27.
[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
75d07914 20=head1 NAME
9c992ba1 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
75d07914 66=item accessor
988bf309 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
75d07914 86restriction. This is currently not used by DBIx::Class.
988bf309 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
75d07914 108currently not used by DBIx::Class.
988bf309 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;
002a359a 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) = @_;
75d07914 170 $self->throw_exception("No such column $column")
701da8c4 171 unless exists $self->_columns->{$column};
5afa2a15 172 #warn $self->{_columns_info_loaded}, "\n";
75d07914 173 if ( ! $self->_columns->{$column}{data_type}
174 and ! $self->{_columns_info_loaded}
8e04bf91 175 and $self->schema and $self->storage )
176 {
177 $self->{_columns_info_loaded}++;
178 my $info;
75d07914 179 # eval for the case of storage without table
8e04bf91 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
002a359a 208=head2 remove_columns
209
210 $table->remove_columns(qw/col1 col2 col3/);
211
212Removes columns from the result source.
213
214=head2 remove_column
215
216 $table->remove_column('col');
217
218Convenience alias to remove_columns.
219
220=cut
221
222sub 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
87c4e602 243=head2 set_primary_key
244
27f01d1f 245=over 4
246
ebc77b53 247=item Arguments: @cols
27f01d1f 248
249=back
87f0da6a 250
9c992ba1 251Defines one or more columns as primary key for this source. Should be
252called after C<add_columns>.
87f0da6a 253
254Additionally, defines a unique constraint named C<primary>.
255
988bf309 256The primary key columns are used by L<DBIx::Class::PK::Auto> to
75d07914 257retrieve automatically created values from the database.
988bf309 258
87f0da6a 259=cut
9c992ba1 260
261sub set_primary_key {
262 my ($self, @cols) = @_;
263 # check if primary key columns are valid columns
8e04bf91 264 foreach my $col (@cols) {
265 $self->throw_exception("No such column $col on table " . $self->name)
266 unless $self->has_column($col);
9c992ba1 267 }
268 $self->_primaries(\@cols);
87f0da6a 269
270 $self->add_unique_constraint(primary => \@cols);
9c992ba1 271}
272
87f0da6a 273=head2 primary_columns
274
9c992ba1 275Read-only accessor which returns the list of primary keys.
30126ac7 276
87f0da6a 277=cut
9c992ba1 278
279sub primary_columns {
280 return @{shift->_primaries||[]};
281}
282
87f0da6a 283=head2 add_unique_constraint
284
285Declare a unique constraint on this source. Call once for each unique
988bf309 286constraint. Unique constraints are used when you call C<find> on a
2053ab2a 287L<DBIx::Class::ResultSet>. Only columns in the constraint are searched,
288for example:
27f01d1f 289
290 # For UNIQUE (column1, column2)
291 __PACKAGE__->add_unique_constraint(
292 constraint_name => [ qw/column1 column2/ ],
293 );
87f0da6a 294
295=cut
296
297sub add_unique_constraint {
298 my ($self, $name, $cols) = @_;
299
8e04bf91 300 foreach my $col (@$cols) {
301 $self->throw_exception("No such column $col on table " . $self->name)
302 unless $self->has_column($col);
87f0da6a 303 }
304
305 my %unique_constraints = $self->unique_constraints;
306 $unique_constraints{$name} = $cols;
307 $self->_unique_constraints(\%unique_constraints);
308}
309
310=head2 unique_constraints
311
312Read-only accessor which returns the list of unique constraints on this source.
313
314=cut
315
316sub unique_constraints {
317 return %{shift->_unique_constraints||{}};
318}
319
9c992ba1 320=head2 from
321
322Returns an expression of the source to be supplied to storage to specify
2053ab2a 323retrieval from this source. In the case of a database, the required FROM
324clause contents.
9c992ba1 325
326=cut
327
328=head2 storage
329
75d07914 330Returns the storage handle for the current schema.
988bf309 331
332See also: L<DBIx::Class::Storage>
9c992ba1 333
334=cut
335
336sub storage { shift->schema->storage; }
337
8452e496 338=head2 add_relationship
339
340 $source->add_relationship('relname', 'related_source', $cond, $attrs);
341
24d67825 342The relationship name can be arbitrary, but must be unique for each
343relationship attached to this result source. 'related_source' should
344be the name with which the related result source was registered with
345the current schema. For example:
8452e496 346
24d67825 347 $schema->source('Book')->add_relationship('reviews', 'Review', {
348 'foreign.book_id' => 'self.id',
349 });
350
2053ab2a 351The condition C<$cond> needs to be an L<SQL::Abstract>-style
24d67825 352representation of the join between the tables. For example, if you're
353creating a rel from Author to Book,
988bf309 354
355 { 'foreign.author_id' => 'self.id' }
356
357will result in the JOIN clause
358
359 author me JOIN book foreign ON foreign.author_id = me.id
360
8452e496 361You can specify as many foreign => self mappings as necessary.
362
988bf309 363Valid attributes are as follows:
364
365=over 4
366
367=item join_type
368
369Explicitly specifies the type of join to use in the relationship. Any
370SQL join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in
371the SQL command immediately before C<JOIN>.
372
373=item proxy
374
24d67825 375An arrayref containing a list of accessors in the foreign class to proxy in
376the main class. If, for example, you do the following:
002a359a 377
24d67825 378 CD->might_have(liner_notes => 'LinerNotes', undef, {
379 proxy => [ qw/notes/ ],
380 });
002a359a 381
24d67825 382Then, assuming LinerNotes has an accessor named notes, you can do:
988bf309 383
24d67825 384 my $cd = CD->find(1);
2053ab2a 385 # set notes -- LinerNotes object is created if it doesn't exist
386 $cd->notes('Notes go here');
988bf309 387
388=item accessor
389
390Specifies the type of accessor that should be created for the
75d07914 391relationship. Valid values are C<single> (for when there is only a single
392related object), C<multi> (when there can be many), and C<filter> (for
393when there is a single related object, but you also want the relationship
394accessor to double as a column accessor). For C<multi> accessors, an
395add_to_* method is also created, which calls C<create_related> for the
988bf309 396relationship.
397
8452e496 398=back
399
400=cut
401
402sub add_relationship {
403 my ($self, $rel, $f_source_name, $cond, $attrs) = @_;
27f01d1f 404 $self->throw_exception("Can't create relationship without join condition")
405 unless $cond;
8452e496 406 $attrs ||= {};
87772e46 407
8452e496 408 my %rels = %{ $self->_relationships };
409 $rels{$rel} = { class => $f_source_name,
87772e46 410 source => $f_source_name,
8452e496 411 cond => $cond,
412 attrs => $attrs };
413 $self->_relationships(\%rels);
414
30126ac7 415 return $self;
87772e46 416
953a18ef 417 # XXX disabled. doesn't work properly currently. skip in tests.
418
8452e496 419 my $f_source = $self->schema->source($f_source_name);
420 unless ($f_source) {
421 eval "require $f_source_name;";
422 if ($@) {
423 die $@ unless $@ =~ /Can't locate/;
424 }
425 $f_source = $f_source_name->result_source;
87772e46 426 #my $s_class = ref($self->schema);
427 #$f_source_name =~ m/^${s_class}::(.*)$/;
428 #$self->schema->register_class(($1 || $f_source_name), $f_source_name);
429 #$f_source = $self->schema->source($f_source_name);
8452e496 430 }
431 return unless $f_source; # Can't test rel without f_source
432
433 eval { $self->resolve_join($rel, 'me') };
434
435 if ($@) { # If the resolve failed, back out and re-throw the error
75d07914 436 delete $rels{$rel}; #
8452e496 437 $self->_relationships(\%rels);
701da8c4 438 $self->throw_exception("Error creating relationship $rel: $@");
8452e496 439 }
440 1;
441}
442
87c4e602 443=head2 relationships
8452e496 444
2053ab2a 445Returns all relationship names for this source.
8452e496 446
447=cut
448
449sub relationships {
450 return keys %{shift->_relationships};
451}
452
87c4e602 453=head2 relationship_info
454
27f01d1f 455=over 4
456
ebc77b53 457=item Arguments: $relname
27f01d1f 458
459=back
8452e496 460
2053ab2a 461Returns a hash of relationship information for the specified relationship
462name.
8452e496 463
464=cut
465
466sub relationship_info {
467 my ($self, $rel) = @_;
468 return $self->_relationships->{$rel};
75d07914 469}
8452e496 470
87c4e602 471=head2 has_relationship
472
27f01d1f 473=over 4
474
ebc77b53 475=item Arguments: $rel
27f01d1f 476
477=back
953a18ef 478
2053ab2a 479Returns true if the source has a relationship of this name, false otherwise.
988bf309 480
481=cut
953a18ef 482
483sub has_relationship {
484 my ($self, $rel) = @_;
485 return exists $self->_relationships->{$rel};
486}
487
de60a93d 488=head2 reverse_relationship_info
489
490=over 4
491
492=item Arguments: $relname
493
494=back
495
496Returns an array of hash references of relationship information for
497the other side of the specified relationship name.
498
499=cut
500
501sub reverse_relationship_info {
502 my ($self, $rel) = @_;
503 my $rel_info = $self->relationship_info($rel);
504 my $ret = {};
505
506 return $ret unless ((ref $rel_info->{cond}) eq 'HASH');
507
508 my @cond = keys(%{$rel_info->{cond}});
509 my @refkeys = map {/^\w+\.(\w+)$/} @cond;
510 my @keys = map {$rel_info->{cond}->{$_} =~ /^\w+\.(\w+)$/} @cond;
511
512 # Get the related result source for this relationship
513 my $othertable = $self->related_source($rel);
514
515 # Get all the relationships for that source that related to this source
516 # whose foreign column set are our self columns on $rel and whose self
517 # columns are our foreign columns on $rel.
518 my @otherrels = $othertable->relationships();
519 my $otherrelationship;
520 foreach my $otherrel (@otherrels) {
521 my $otherrel_info = $othertable->relationship_info($otherrel);
522
523 my $back = $othertable->related_source($otherrel);
524 next unless $back->name eq $self->name;
525
526 my @othertestconds;
527
528 if (ref $otherrel_info->{cond} eq 'HASH') {
529 @othertestconds = ($otherrel_info->{cond});
530 }
531 elsif (ref $otherrel_info->{cond} eq 'ARRAY') {
532 @othertestconds = @{$otherrel_info->{cond}};
533 }
534 else {
535 next;
536 }
537
538 foreach my $othercond (@othertestconds) {
539 my @other_cond = keys(%$othercond);
540 my @other_refkeys = map {/^\w+\.(\w+)$/} @other_cond;
541 my @other_keys = map {$othercond->{$_} =~ /^\w+\.(\w+)$/} @other_cond;
542 next if (!$self->compare_relationship_keys(\@refkeys, \@other_keys) ||
543 !$self->compare_relationship_keys(\@other_refkeys, \@keys));
544 $ret->{$otherrel} = $otherrel_info;
545 }
546 }
547 return $ret;
548}
549
550=head2 compare_relationship_keys
551
552=over 4
553
554=item Arguments: $keys1, $keys2
555
556=back
557
558Returns true if both sets of keynames are the same, false otherwise.
559
560=cut
561
562sub compare_relationship_keys {
563 my ($self, $keys1, $keys2) = @_;
564
565 # Make sure every keys1 is in keys2
566 my $found;
567 foreach my $key (@$keys1) {
568 $found = 0;
569 foreach my $prim (@$keys2) {
570 if ($prim eq $key) {
571 $found = 1;
572 last;
573 }
574 }
575 last unless $found;
576 }
577
578 # Make sure every key2 is in key1
579 if ($found) {
580 foreach my $prim (@$keys2) {
581 $found = 0;
582 foreach my $key (@$keys1) {
583 if ($prim eq $key) {
584 $found = 1;
585 last;
586 }
587 }
588 last unless $found;
589 }
590 }
591
592 return $found;
593}
594
87c4e602 595=head2 resolve_join
596
27f01d1f 597=over 4
598
ebc77b53 599=item Arguments: $relation
27f01d1f 600
601=back
8452e496 602
2053ab2a 603Returns the join structure required for the related result source.
8452e496 604
605=cut
606
607sub resolve_join {
489709af 608 my ($self, $join, $alias, $seen) = @_;
609 $seen ||= {};
87772e46 610 if (ref $join eq 'ARRAY') {
489709af 611 return map { $self->resolve_join($_, $alias, $seen) } @$join;
87772e46 612 } elsif (ref $join eq 'HASH') {
489709af 613 return
887ce227 614 map {
615 my $as = ($seen->{$_} ? $_.'_'.($seen->{$_}+1) : $_);
616 ($self->resolve_join($_, $alias, $seen),
617 $self->related_source($_)->resolve_join($join->{$_}, $as, $seen));
618 } keys %$join;
87772e46 619 } elsif (ref $join) {
701da8c4 620 $self->throw_exception("No idea how to resolve join reftype ".ref $join);
87772e46 621 } else {
489709af 622 my $count = ++$seen->{$join};
623 #use Data::Dumper; warn Dumper($seen);
624 my $as = ($count > 1 ? "${join}_${count}" : $join);
3842b955 625 my $rel_info = $self->relationship_info($join);
701da8c4 626 $self->throw_exception("No such relationship ${join}") unless $rel_info;
3842b955 627 my $type = $rel_info->{attrs}{join_type} || '';
489709af 628 return [ { $as => $self->related_source($join)->from,
953a18ef 629 -join_type => $type },
489709af 630 $self->resolve_condition($rel_info->{cond}, $as, $alias) ];
953a18ef 631 }
632}
633
87c4e602 634=head2 resolve_condition
635
27f01d1f 636=over 4
637
ebc77b53 638=item Arguments: $cond, $as, $alias|$object
27f01d1f 639
640=back
953a18ef 641
3842b955 642Resolves the passed condition to a concrete query fragment. If given an alias,
953a18ef 643returns a join condition; if given an object, inverts that object to produce
644a related conditional from that object.
645
646=cut
647
648sub resolve_condition {
489709af 649 my ($self, $cond, $as, $for) = @_;
953a18ef 650 #warn %$cond;
651 if (ref $cond eq 'HASH') {
652 my %ret;
653 while (my ($k, $v) = each %{$cond}) {
654 # XXX should probably check these are valid columns
27f01d1f 655 $k =~ s/^foreign\.// ||
75d07914 656 $self->throw_exception("Invalid rel cond key ${k}");
27f01d1f 657 $v =~ s/^self\.// ||
75d07914 658 $self->throw_exception("Invalid rel cond val ${v}");
953a18ef 659 if (ref $for) { # Object
3842b955 660 #warn "$self $k $for $v";
661 $ret{$k} = $for->get_column($v);
662 #warn %ret;
fde6e28e 663 } elsif (ref $as) { # reverse object
664 $ret{$v} = $as->get_column($k);
953a18ef 665 } else {
489709af 666 $ret{"${as}.${k}"} = "${for}.${v}";
953a18ef 667 }
953a18ef 668 }
669 return \%ret;
5efe4c79 670 } elsif (ref $cond eq 'ARRAY') {
489709af 671 return [ map { $self->resolve_condition($_, $as, $for) } @$cond ];
953a18ef 672 } else {
673 die("Can't handle this yet :(");
87772e46 674 }
675}
676
87c4e602 677=head2 resolve_prefetch
678
27f01d1f 679=over 4
680
ebc77b53 681=item Arguments: hashref/arrayref/scalar
27f01d1f 682
683=back
988bf309 684
b3e8ac9b 685Accepts one or more relationships for the current source and returns an
686array of column names for each of those relationships. Column names are
687prefixed relative to the current source, in accordance with where they appear
688in the supplied relationships. Examples:
689
5ac6a044 690 my $source = $schema->resultset('Tag')->source;
b3e8ac9b 691 @columns = $source->resolve_prefetch( { cd => 'artist' } );
692
693 # @columns =
694 #(
695 # 'cd.cdid',
696 # 'cd.artist',
697 # 'cd.title',
698 # 'cd.year',
699 # 'cd.artist.artistid',
700 # 'cd.artist.name'
701 #)
702
703 @columns = $source->resolve_prefetch( qw[/ cd /] );
704
705 # @columns =
706 #(
707 # 'cd.cdid',
708 # 'cd.artist',
709 # 'cd.title',
710 # 'cd.year'
711 #)
712
713 $source = $schema->resultset('CD')->source;
714 @columns = $source->resolve_prefetch( qw[/ artist producer /] );
715
716 # @columns =
717 #(
718 # 'artist.artistid',
719 # 'artist.name',
720 # 'producer.producerid',
721 # 'producer.name'
75d07914 722 #)
988bf309 723
b3e8ac9b 724=cut
725
726sub resolve_prefetch {
0f66a01b 727 my ($self, $pre, $alias, $seen, $order, $collapse) = @_;
489709af 728 $seen ||= {};
b3e8ac9b 729 #$alias ||= $self->name;
730 #warn $alias, Dumper $pre;
731 if( ref $pre eq 'ARRAY' ) {
0f66a01b 732 return
733 map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) }
734 @$pre;
b3e8ac9b 735 }
736 elsif( ref $pre eq 'HASH' ) {
737 my @ret =
738 map {
0f66a01b 739 $self->resolve_prefetch($_, $alias, $seen, $order, $collapse),
489709af 740 $self->related_source($_)->resolve_prefetch(
0f66a01b 741 $pre->{$_}, "${alias}.$_", $seen, $order, $collapse)
742 } keys %$pre;
b3e8ac9b 743 #die Dumper \@ret;
744 return @ret;
745 }
746 elsif( ref $pre ) {
a86b1efe 747 $self->throw_exception(
748 "don't know how to resolve prefetch reftype ".ref($pre));
b3e8ac9b 749 }
750 else {
489709af 751 my $count = ++$seen->{$pre};
752 my $as = ($count > 1 ? "${pre}_${count}" : $pre);
b3e8ac9b 753 my $rel_info = $self->relationship_info( $pre );
a86b1efe 754 $self->throw_exception( $self->name . " has no such relationship '$pre'" )
755 unless $rel_info;
37f23589 756 my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
a86b1efe 757 my $rel_source = $self->related_source($pre);
0f66a01b 758
759 if (exists $rel_info->{attrs}{accessor}
760 && $rel_info->{attrs}{accessor} eq 'multi') {
761 $self->throw_exception(
762 "Can't prefetch has_many ${pre} (join cond too complex)")
763 unless ref($rel_info->{cond}) eq 'HASH';
37f23589 764 my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
0f66a01b 765 keys %{$rel_info->{cond}};
766 $collapse->{"${as_prefix}${pre}"} = \@key;
5a5bec6c 767 my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
768 ? @{$rel_info->{attrs}{order_by}}
769 : (defined $rel_info->{attrs}{order_by}
770 ? ($rel_info->{attrs}{order_by})
771 : ()));
772 push(@$order, map { "${as}.$_" } (@key, @ord));
0f66a01b 773 }
774
489709af 775 return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
a86b1efe 776 $rel_source->columns;
b3e8ac9b 777 #warn $alias, Dumper (\@ret);
489709af 778 #return @ret;
b3e8ac9b 779 }
780}
953a18ef 781
87c4e602 782=head2 related_source
783
27f01d1f 784=over 4
785
ebc77b53 786=item Arguments: $relname
27f01d1f 787
788=back
87772e46 789
2053ab2a 790Returns the result source object for the given relationship.
87772e46 791
792=cut
793
794sub related_source {
795 my ($self, $rel) = @_;
aea52c85 796 if( !$self->has_relationship( $rel ) ) {
701da8c4 797 $self->throw_exception("No such relationship '$rel'");
aea52c85 798 }
87772e46 799 return $self->schema->source($self->relationship_info($rel)->{source});
8452e496 800}
801
77254782 802=head2 related_class
803
27f01d1f 804=over 4
805
ebc77b53 806=item Arguments: $relname
27f01d1f 807
808=back
77254782 809
2053ab2a 810Returns the class name for objects in the given relationship.
77254782 811
812=cut
813
814sub related_class {
815 my ($self, $rel) = @_;
816 if( !$self->has_relationship( $rel ) ) {
817 $self->throw_exception("No such relationship '$rel'");
818 }
819 return $self->schema->class($self->relationship_info($rel)->{source});
820}
821
5ac6a044 822=head2 resultset
823
bcc5a210 824Returns a resultset for the given source. This will initially be created
825on demand by calling
5ac6a044 826
988bf309 827 $self->resultset_class->new($self, $self->resultset_attributes)
5ac6a044 828
bcc5a210 829but is cached from then on unless resultset_class changes.
830
5ac6a044 831=head2 resultset_class
832
988bf309 833Set the class of the resultset, this is useful if you want to create your
834own resultset methods. Create your own class derived from
835L<DBIx::Class::ResultSet>, and set it here.
5ac6a044 836
837=head2 resultset_attributes
838
988bf309 839Specify here any attributes you wish to pass to your specialised resultset.
5ac6a044 840
841=cut
842
843sub resultset {
844 my $self = shift;
27f01d1f 845 $self->throw_exception(
846 'resultset does not take any arguments. If you want another resultset, '.
847 'call it on the schema instead.'
848 ) if scalar @_;
849 return $self->{_resultset}
850 if ref $self->{_resultset} eq $self->resultset_class;
851 return $self->{_resultset} = $self->resultset_class->new(
852 $self, $self->{resultset_attributes}
853 );
5ac6a044 854}
855
701da8c4 856=head2 throw_exception
857
2053ab2a 858See L<DBIx::Class::Schema/"throw_exception">.
701da8c4 859
860=cut
861
862sub throw_exception {
863 my $self = shift;
75d07914 864 if (defined $self->schema) {
701da8c4 865 $self->schema->throw_exception(@_);
866 } else {
867 croak(@_);
868 }
869}
870
9c992ba1 871=head1 AUTHORS
872
873Matt S. Trout <mst@shadowcatsystems.co.uk>
874
875=head1 LICENSE
876
877You may distribute this code under the same terms as Perl itself.
878
879=cut
880