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