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