Merge 'trunk' into 'DBIx-Class-current'
[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
e6a0e17c 321=head2 unique_constraint_names
322
323Returns the list of unique constraint names defined on this source.
324
325=cut
326
327sub 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
337Returns the list of columns that make up the specified unique constraint.
338
339=cut
340
341sub 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
9c992ba1 353=head2 from
354
355Returns an expression of the source to be supplied to storage to specify
2053ab2a 356retrieval from this source. In the case of a database, the required FROM
357clause contents.
9c992ba1 358
359=cut
360
361=head2 storage
362
75d07914 363Returns the storage handle for the current schema.
988bf309 364
365See also: L<DBIx::Class::Storage>
9c992ba1 366
367=cut
368
369sub storage { shift->schema->storage; }
370
8452e496 371=head2 add_relationship
372
373 $source->add_relationship('relname', 'related_source', $cond, $attrs);
374
24d67825 375The relationship name can be arbitrary, but must be unique for each
376relationship attached to this result source. 'related_source' should
377be the name with which the related result source was registered with
378the current schema. For example:
8452e496 379
24d67825 380 $schema->source('Book')->add_relationship('reviews', 'Review', {
381 'foreign.book_id' => 'self.id',
382 });
383
2053ab2a 384The condition C<$cond> needs to be an L<SQL::Abstract>-style
24d67825 385representation of the join between the tables. For example, if you're
386creating a rel from Author to Book,
988bf309 387
388 { 'foreign.author_id' => 'self.id' }
389
390will result in the JOIN clause
391
392 author me JOIN book foreign ON foreign.author_id = me.id
393
8452e496 394You can specify as many foreign => self mappings as necessary.
395
988bf309 396Valid attributes are as follows:
397
398=over 4
399
400=item join_type
401
402Explicitly specifies the type of join to use in the relationship. Any
403SQL join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in
404the SQL command immediately before C<JOIN>.
405
406=item proxy
407
24d67825 408An arrayref containing a list of accessors in the foreign class to proxy in
409the main class. If, for example, you do the following:
002a359a 410
24d67825 411 CD->might_have(liner_notes => 'LinerNotes', undef, {
412 proxy => [ qw/notes/ ],
413 });
002a359a 414
24d67825 415Then, assuming LinerNotes has an accessor named notes, you can do:
988bf309 416
24d67825 417 my $cd = CD->find(1);
2053ab2a 418 # set notes -- LinerNotes object is created if it doesn't exist
419 $cd->notes('Notes go here');
988bf309 420
421=item accessor
422
423Specifies the type of accessor that should be created for the
75d07914 424relationship. Valid values are C<single> (for when there is only a single
425related object), C<multi> (when there can be many), and C<filter> (for
426when there is a single related object, but you also want the relationship
427accessor to double as a column accessor). For C<multi> accessors, an
428add_to_* method is also created, which calls C<create_related> for the
988bf309 429relationship.
430
8452e496 431=back
432
433=cut
434
435sub add_relationship {
436 my ($self, $rel, $f_source_name, $cond, $attrs) = @_;
27f01d1f 437 $self->throw_exception("Can't create relationship without join condition")
438 unless $cond;
8452e496 439 $attrs ||= {};
87772e46 440
8452e496 441 my %rels = %{ $self->_relationships };
442 $rels{$rel} = { class => $f_source_name,
87772e46 443 source => $f_source_name,
8452e496 444 cond => $cond,
445 attrs => $attrs };
446 $self->_relationships(\%rels);
447
30126ac7 448 return $self;
87772e46 449
953a18ef 450 # XXX disabled. doesn't work properly currently. skip in tests.
451
8452e496 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;
87772e46 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);
8452e496 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
75d07914 469 delete $rels{$rel}; #
8452e496 470 $self->_relationships(\%rels);
701da8c4 471 $self->throw_exception("Error creating relationship $rel: $@");
8452e496 472 }
473 1;
474}
475
87c4e602 476=head2 relationships
8452e496 477
2053ab2a 478Returns all relationship names for this source.
8452e496 479
480=cut
481
482sub relationships {
483 return keys %{shift->_relationships};
484}
485
87c4e602 486=head2 relationship_info
487
27f01d1f 488=over 4
489
ebc77b53 490=item Arguments: $relname
27f01d1f 491
492=back
8452e496 493
2053ab2a 494Returns a hash of relationship information for the specified relationship
495name.
8452e496 496
497=cut
498
499sub relationship_info {
500 my ($self, $rel) = @_;
501 return $self->_relationships->{$rel};
75d07914 502}
8452e496 503
87c4e602 504=head2 has_relationship
505
27f01d1f 506=over 4
507
ebc77b53 508=item Arguments: $rel
27f01d1f 509
510=back
953a18ef 511
2053ab2a 512Returns true if the source has a relationship of this name, false otherwise.
988bf309 513
514=cut
953a18ef 515
516sub has_relationship {
517 my ($self, $rel) = @_;
518 return exists $self->_relationships->{$rel};
519}
520
de60a93d 521=head2 reverse_relationship_info
522
523=over 4
524
525=item Arguments: $relname
526
527=back
528
bab77431 529Returns an array of hash references of relationship information for
de60a93d 530the other side of the specified relationship name.
531
532=cut
533
534sub 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;
bab77431 544
de60a93d 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
bab77431 550 # columns are our foreign columns on $rel.
de60a93d 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;
bab77431 575 next if (!$self->compare_relationship_keys(\@refkeys, \@other_keys) ||
de60a93d 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
591Returns true if both sets of keynames are the same, false otherwise.
592
593=cut
594
595sub 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
87c4e602 628=head2 resolve_join
629
27f01d1f 630=over 4
631
ebc77b53 632=item Arguments: $relation
27f01d1f 633
634=back
8452e496 635
2053ab2a 636Returns the join structure required for the related result source.
8452e496 637
638=cut
639
640sub resolve_join {
489709af 641 my ($self, $join, $alias, $seen) = @_;
642 $seen ||= {};
87772e46 643 if (ref $join eq 'ARRAY') {
489709af 644 return map { $self->resolve_join($_, $alias, $seen) } @$join;
87772e46 645 } elsif (ref $join eq 'HASH') {
489709af 646 return
887ce227 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;
87772e46 652 } elsif (ref $join) {
701da8c4 653 $self->throw_exception("No idea how to resolve join reftype ".ref $join);
87772e46 654 } else {
489709af 655 my $count = ++$seen->{$join};
656 #use Data::Dumper; warn Dumper($seen);
657 my $as = ($count > 1 ? "${join}_${count}" : $join);
3842b955 658 my $rel_info = $self->relationship_info($join);
701da8c4 659 $self->throw_exception("No such relationship ${join}") unless $rel_info;
3842b955 660 my $type = $rel_info->{attrs}{join_type} || '';
489709af 661 return [ { $as => $self->related_source($join)->from,
953a18ef 662 -join_type => $type },
489709af 663 $self->resolve_condition($rel_info->{cond}, $as, $alias) ];
953a18ef 664 }
665}
666
87c4e602 667=head2 resolve_condition
668
27f01d1f 669=over 4
670
ebc77b53 671=item Arguments: $cond, $as, $alias|$object
27f01d1f 672
673=back
953a18ef 674
3842b955 675Resolves the passed condition to a concrete query fragment. If given an alias,
953a18ef 676returns a join condition; if given an object, inverts that object to produce
677a related conditional from that object.
678
679=cut
680
681sub resolve_condition {
489709af 682 my ($self, $cond, $as, $for) = @_;
953a18ef 683 #warn %$cond;
684 if (ref $cond eq 'HASH') {
685 my %ret;
bd054cb4 686 foreach my $k (keys %{$cond}) {
687 my $v = $cond->{$k};
953a18ef 688 # XXX should probably check these are valid columns
27f01d1f 689 $k =~ s/^foreign\.// ||
75d07914 690 $self->throw_exception("Invalid rel cond key ${k}");
27f01d1f 691 $v =~ s/^self\.// ||
75d07914 692 $self->throw_exception("Invalid rel cond val ${v}");
953a18ef 693 if (ref $for) { # Object
3842b955 694 #warn "$self $k $for $v";
695 $ret{$k} = $for->get_column($v);
696 #warn %ret;
2c037e6b 697 } elsif (!defined $for) { # undef, i.e. "no object"
698 $ret{$k} = undef;
fde6e28e 699 } elsif (ref $as) { # reverse object
700 $ret{$v} = $as->get_column($k);
2c037e6b 701 } elsif (!defined $as) { # undef, i.e. "no reverse object"
702 $ret{$v} = undef;
953a18ef 703 } else {
489709af 704 $ret{"${as}.${k}"} = "${for}.${v}";
953a18ef 705 }
953a18ef 706 }
707 return \%ret;
5efe4c79 708 } elsif (ref $cond eq 'ARRAY') {
489709af 709 return [ map { $self->resolve_condition($_, $as, $for) } @$cond ];
953a18ef 710 } else {
711 die("Can't handle this yet :(");
87772e46 712 }
713}
714
87c4e602 715=head2 resolve_prefetch
716
27f01d1f 717=over 4
718
ebc77b53 719=item Arguments: hashref/arrayref/scalar
27f01d1f 720
721=back
988bf309 722
b3e8ac9b 723Accepts one or more relationships for the current source and returns an
724array of column names for each of those relationships. Column names are
725prefixed relative to the current source, in accordance with where they appear
726in the supplied relationships. Examples:
727
5ac6a044 728 my $source = $schema->resultset('Tag')->source;
b3e8ac9b 729 @columns = $source->resolve_prefetch( { cd => 'artist' } );
730
731 # @columns =
732 #(
733 # 'cd.cdid',
734 # 'cd.artist',
735 # 'cd.title',
736 # 'cd.year',
737 # 'cd.artist.artistid',
738 # 'cd.artist.name'
739 #)
740
741 @columns = $source->resolve_prefetch( qw[/ cd /] );
742
743 # @columns =
744 #(
745 # 'cd.cdid',
746 # 'cd.artist',
747 # 'cd.title',
748 # 'cd.year'
749 #)
750
751 $source = $schema->resultset('CD')->source;
752 @columns = $source->resolve_prefetch( qw[/ artist producer /] );
753
754 # @columns =
755 #(
756 # 'artist.artistid',
757 # 'artist.name',
758 # 'producer.producerid',
759 # 'producer.name'
75d07914 760 #)
988bf309 761
b3e8ac9b 762=cut
763
764sub resolve_prefetch {
0f66a01b 765 my ($self, $pre, $alias, $seen, $order, $collapse) = @_;
489709af 766 $seen ||= {};
b3e8ac9b 767 #$alias ||= $self->name;
768 #warn $alias, Dumper $pre;
769 if( ref $pre eq 'ARRAY' ) {
0f66a01b 770 return
771 map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) }
772 @$pre;
b3e8ac9b 773 }
774 elsif( ref $pre eq 'HASH' ) {
775 my @ret =
776 map {
0f66a01b 777 $self->resolve_prefetch($_, $alias, $seen, $order, $collapse),
489709af 778 $self->related_source($_)->resolve_prefetch(
0f66a01b 779 $pre->{$_}, "${alias}.$_", $seen, $order, $collapse)
780 } keys %$pre;
b3e8ac9b 781 #die Dumper \@ret;
782 return @ret;
783 }
784 elsif( ref $pre ) {
a86b1efe 785 $self->throw_exception(
786 "don't know how to resolve prefetch reftype ".ref($pre));
b3e8ac9b 787 }
788 else {
489709af 789 my $count = ++$seen->{$pre};
790 my $as = ($count > 1 ? "${pre}_${count}" : $pre);
b3e8ac9b 791 my $rel_info = $self->relationship_info( $pre );
a86b1efe 792 $self->throw_exception( $self->name . " has no such relationship '$pre'" )
793 unless $rel_info;
37f23589 794 my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
a86b1efe 795 my $rel_source = $self->related_source($pre);
0f66a01b 796
797 if (exists $rel_info->{attrs}{accessor}
798 && $rel_info->{attrs}{accessor} eq 'multi') {
799 $self->throw_exception(
800 "Can't prefetch has_many ${pre} (join cond too complex)")
801 unless ref($rel_info->{cond}) eq 'HASH';
37f23589 802 my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
0f66a01b 803 keys %{$rel_info->{cond}};
804 $collapse->{"${as_prefix}${pre}"} = \@key;
5a5bec6c 805 my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
806 ? @{$rel_info->{attrs}{order_by}}
807 : (defined $rel_info->{attrs}{order_by}
808 ? ($rel_info->{attrs}{order_by})
809 : ()));
810 push(@$order, map { "${as}.$_" } (@key, @ord));
0f66a01b 811 }
812
489709af 813 return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
a86b1efe 814 $rel_source->columns;
b3e8ac9b 815 #warn $alias, Dumper (\@ret);
489709af 816 #return @ret;
b3e8ac9b 817 }
818}
953a18ef 819
87c4e602 820=head2 related_source
821
27f01d1f 822=over 4
823
ebc77b53 824=item Arguments: $relname
27f01d1f 825
826=back
87772e46 827
2053ab2a 828Returns the result source object for the given relationship.
87772e46 829
830=cut
831
832sub related_source {
833 my ($self, $rel) = @_;
aea52c85 834 if( !$self->has_relationship( $rel ) ) {
701da8c4 835 $self->throw_exception("No such relationship '$rel'");
aea52c85 836 }
87772e46 837 return $self->schema->source($self->relationship_info($rel)->{source});
8452e496 838}
839
77254782 840=head2 related_class
841
27f01d1f 842=over 4
843
ebc77b53 844=item Arguments: $relname
27f01d1f 845
846=back
77254782 847
2053ab2a 848Returns the class name for objects in the given relationship.
77254782 849
850=cut
851
852sub related_class {
853 my ($self, $rel) = @_;
854 if( !$self->has_relationship( $rel ) ) {
855 $self->throw_exception("No such relationship '$rel'");
856 }
857 return $self->schema->class($self->relationship_info($rel)->{source});
858}
859
5ac6a044 860=head2 resultset
861
bcc5a210 862Returns a resultset for the given source. This will initially be created
863on demand by calling
5ac6a044 864
988bf309 865 $self->resultset_class->new($self, $self->resultset_attributes)
5ac6a044 866
bcc5a210 867but is cached from then on unless resultset_class changes.
868
5ac6a044 869=head2 resultset_class
870
988bf309 871Set the class of the resultset, this is useful if you want to create your
872own resultset methods. Create your own class derived from
873L<DBIx::Class::ResultSet>, and set it here.
5ac6a044 874
875=head2 resultset_attributes
876
988bf309 877Specify here any attributes you wish to pass to your specialised resultset.
5ac6a044 878
879=cut
880
881sub resultset {
882 my $self = shift;
27f01d1f 883 $self->throw_exception(
884 'resultset does not take any arguments. If you want another resultset, '.
885 'call it on the schema instead.'
886 ) if scalar @_;
428c2b82 887
888 # disabled until we can figure out a way to do it without consistency issues
889 #
890 #return $self->{_resultset}
891 # if ref $self->{_resultset} eq $self->resultset_class;
892 #return $self->{_resultset} =
893
894 return $self->resultset_class->new(
27f01d1f 895 $self, $self->{resultset_attributes}
896 );
5ac6a044 897}
898
bab77431 899=head2 source_name
900
901=over 4
902
903=item Arguments: $source_name
904
905=back
906
907Set the name of the result source when it is loaded into a schema.
908This is usefull if you want to refer to a result source by a name other than
909its class name.
910
911 package ArchivedBooks;
912 use base qw/DBIx::Class/;
913 __PACKAGE__->table('books_archive');
914 __PACKAGE__->source_name('Books');
915
916 # from your schema...
917 $schema->resultset('Books')->find(1);
918
701da8c4 919=head2 throw_exception
920
2053ab2a 921See L<DBIx::Class::Schema/"throw_exception">.
701da8c4 922
923=cut
924
925sub throw_exception {
926 my $self = shift;
75d07914 927 if (defined $self->schema) {
701da8c4 928 $self->schema->throw_exception(@_);
929 } else {
930 croak(@_);
931 }
932}
933
9c992ba1 934=head1 AUTHORS
935
936Matt S. Trout <mst@shadowcatsystems.co.uk>
937
938=head1 LICENSE
939
940You may distribute this code under the same terms as Perl itself.
941
942=cut
943