Add a warning for DBD::Pg < 1.49
[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) {
c037c03a 459 $self->ensure_class_loaded($f_source_name);
8452e496 460 $f_source = $f_source_name->result_source;
87772e46 461 #my $s_class = ref($self->schema);
462 #$f_source_name =~ m/^${s_class}::(.*)$/;
463 #$self->schema->register_class(($1 || $f_source_name), $f_source_name);
464 #$f_source = $self->schema->source($f_source_name);
8452e496 465 }
466 return unless $f_source; # Can't test rel without f_source
467
468 eval { $self->resolve_join($rel, 'me') };
469
470 if ($@) { # If the resolve failed, back out and re-throw the error
75d07914 471 delete $rels{$rel}; #
8452e496 472 $self->_relationships(\%rels);
701da8c4 473 $self->throw_exception("Error creating relationship $rel: $@");
8452e496 474 }
475 1;
476}
477
87c4e602 478=head2 relationships
8452e496 479
2053ab2a 480Returns all relationship names for this source.
8452e496 481
482=cut
483
484sub relationships {
485 return keys %{shift->_relationships};
486}
487
87c4e602 488=head2 relationship_info
489
27f01d1f 490=over 4
491
ebc77b53 492=item Arguments: $relname
27f01d1f 493
494=back
8452e496 495
2053ab2a 496Returns a hash of relationship information for the specified relationship
497name.
8452e496 498
499=cut
500
501sub relationship_info {
502 my ($self, $rel) = @_;
503 return $self->_relationships->{$rel};
75d07914 504}
8452e496 505
87c4e602 506=head2 has_relationship
507
27f01d1f 508=over 4
509
ebc77b53 510=item Arguments: $rel
27f01d1f 511
512=back
953a18ef 513
2053ab2a 514Returns true if the source has a relationship of this name, false otherwise.
988bf309 515
516=cut
953a18ef 517
518sub has_relationship {
519 my ($self, $rel) = @_;
520 return exists $self->_relationships->{$rel};
521}
522
de60a93d 523=head2 reverse_relationship_info
524
525=over 4
526
527=item Arguments: $relname
528
529=back
530
bab77431 531Returns an array of hash references of relationship information for
de60a93d 532the other side of the specified relationship name.
533
534=cut
535
536sub reverse_relationship_info {
537 my ($self, $rel) = @_;
538 my $rel_info = $self->relationship_info($rel);
539 my $ret = {};
540
541 return $ret unless ((ref $rel_info->{cond}) eq 'HASH');
542
543 my @cond = keys(%{$rel_info->{cond}});
544 my @refkeys = map {/^\w+\.(\w+)$/} @cond;
545 my @keys = map {$rel_info->{cond}->{$_} =~ /^\w+\.(\w+)$/} @cond;
bab77431 546
de60a93d 547 # Get the related result source for this relationship
548 my $othertable = $self->related_source($rel);
549
550 # Get all the relationships for that source that related to this source
551 # whose foreign column set are our self columns on $rel and whose self
bab77431 552 # columns are our foreign columns on $rel.
de60a93d 553 my @otherrels = $othertable->relationships();
554 my $otherrelationship;
555 foreach my $otherrel (@otherrels) {
556 my $otherrel_info = $othertable->relationship_info($otherrel);
557
558 my $back = $othertable->related_source($otherrel);
559 next unless $back->name eq $self->name;
560
561 my @othertestconds;
562
563 if (ref $otherrel_info->{cond} eq 'HASH') {
564 @othertestconds = ($otherrel_info->{cond});
565 }
566 elsif (ref $otherrel_info->{cond} eq 'ARRAY') {
567 @othertestconds = @{$otherrel_info->{cond}};
568 }
569 else {
570 next;
571 }
572
573 foreach my $othercond (@othertestconds) {
574 my @other_cond = keys(%$othercond);
575 my @other_refkeys = map {/^\w+\.(\w+)$/} @other_cond;
576 my @other_keys = map {$othercond->{$_} =~ /^\w+\.(\w+)$/} @other_cond;
bab77431 577 next if (!$self->compare_relationship_keys(\@refkeys, \@other_keys) ||
de60a93d 578 !$self->compare_relationship_keys(\@other_refkeys, \@keys));
579 $ret->{$otherrel} = $otherrel_info;
580 }
581 }
582 return $ret;
583}
584
585=head2 compare_relationship_keys
586
587=over 4
588
589=item Arguments: $keys1, $keys2
590
591=back
592
593Returns true if both sets of keynames are the same, false otherwise.
594
595=cut
596
597sub compare_relationship_keys {
598 my ($self, $keys1, $keys2) = @_;
599
600 # Make sure every keys1 is in keys2
601 my $found;
602 foreach my $key (@$keys1) {
603 $found = 0;
604 foreach my $prim (@$keys2) {
605 if ($prim eq $key) {
606 $found = 1;
607 last;
608 }
609 }
610 last unless $found;
611 }
612
613 # Make sure every key2 is in key1
614 if ($found) {
615 foreach my $prim (@$keys2) {
616 $found = 0;
617 foreach my $key (@$keys1) {
618 if ($prim eq $key) {
619 $found = 1;
620 last;
621 }
622 }
623 last unless $found;
624 }
625 }
626
627 return $found;
628}
629
87c4e602 630=head2 resolve_join
631
27f01d1f 632=over 4
633
ebc77b53 634=item Arguments: $relation
27f01d1f 635
636=back
8452e496 637
2053ab2a 638Returns the join structure required for the related result source.
8452e496 639
640=cut
641
642sub resolve_join {
489709af 643 my ($self, $join, $alias, $seen) = @_;
644 $seen ||= {};
87772e46 645 if (ref $join eq 'ARRAY') {
489709af 646 return map { $self->resolve_join($_, $alias, $seen) } @$join;
87772e46 647 } elsif (ref $join eq 'HASH') {
489709af 648 return
887ce227 649 map {
650 my $as = ($seen->{$_} ? $_.'_'.($seen->{$_}+1) : $_);
651 ($self->resolve_join($_, $alias, $seen),
652 $self->related_source($_)->resolve_join($join->{$_}, $as, $seen));
653 } keys %$join;
87772e46 654 } elsif (ref $join) {
701da8c4 655 $self->throw_exception("No idea how to resolve join reftype ".ref $join);
87772e46 656 } else {
489709af 657 my $count = ++$seen->{$join};
658 #use Data::Dumper; warn Dumper($seen);
659 my $as = ($count > 1 ? "${join}_${count}" : $join);
3842b955 660 my $rel_info = $self->relationship_info($join);
701da8c4 661 $self->throw_exception("No such relationship ${join}") unless $rel_info;
3842b955 662 my $type = $rel_info->{attrs}{join_type} || '';
489709af 663 return [ { $as => $self->related_source($join)->from,
953a18ef 664 -join_type => $type },
489709af 665 $self->resolve_condition($rel_info->{cond}, $as, $alias) ];
953a18ef 666 }
667}
668
87c4e602 669=head2 resolve_condition
670
27f01d1f 671=over 4
672
ebc77b53 673=item Arguments: $cond, $as, $alias|$object
27f01d1f 674
675=back
953a18ef 676
3842b955 677Resolves the passed condition to a concrete query fragment. If given an alias,
953a18ef 678returns a join condition; if given an object, inverts that object to produce
679a related conditional from that object.
680
681=cut
682
683sub resolve_condition {
489709af 684 my ($self, $cond, $as, $for) = @_;
953a18ef 685 #warn %$cond;
686 if (ref $cond eq 'HASH') {
687 my %ret;
bd054cb4 688 foreach my $k (keys %{$cond}) {
689 my $v = $cond->{$k};
953a18ef 690 # XXX should probably check these are valid columns
27f01d1f 691 $k =~ s/^foreign\.// ||
75d07914 692 $self->throw_exception("Invalid rel cond key ${k}");
27f01d1f 693 $v =~ s/^self\.// ||
75d07914 694 $self->throw_exception("Invalid rel cond val ${v}");
953a18ef 695 if (ref $for) { # Object
3842b955 696 #warn "$self $k $for $v";
697 $ret{$k} = $for->get_column($v);
698 #warn %ret;
2c037e6b 699 } elsif (!defined $for) { # undef, i.e. "no object"
700 $ret{$k} = undef;
fde6e28e 701 } elsif (ref $as) { # reverse object
702 $ret{$v} = $as->get_column($k);
2c037e6b 703 } elsif (!defined $as) { # undef, i.e. "no reverse object"
704 $ret{$v} = undef;
953a18ef 705 } else {
489709af 706 $ret{"${as}.${k}"} = "${for}.${v}";
953a18ef 707 }
953a18ef 708 }
709 return \%ret;
5efe4c79 710 } elsif (ref $cond eq 'ARRAY') {
489709af 711 return [ map { $self->resolve_condition($_, $as, $for) } @$cond ];
953a18ef 712 } else {
713 die("Can't handle this yet :(");
87772e46 714 }
715}
716
87c4e602 717=head2 resolve_prefetch
718
27f01d1f 719=over 4
720
ebc77b53 721=item Arguments: hashref/arrayref/scalar
27f01d1f 722
723=back
988bf309 724
b3e8ac9b 725Accepts one or more relationships for the current source and returns an
726array of column names for each of those relationships. Column names are
727prefixed relative to the current source, in accordance with where they appear
728in the supplied relationships. Examples:
729
5ac6a044 730 my $source = $schema->resultset('Tag')->source;
b3e8ac9b 731 @columns = $source->resolve_prefetch( { cd => 'artist' } );
732
733 # @columns =
734 #(
735 # 'cd.cdid',
736 # 'cd.artist',
737 # 'cd.title',
738 # 'cd.year',
739 # 'cd.artist.artistid',
740 # 'cd.artist.name'
741 #)
742
743 @columns = $source->resolve_prefetch( qw[/ cd /] );
744
745 # @columns =
746 #(
747 # 'cd.cdid',
748 # 'cd.artist',
749 # 'cd.title',
750 # 'cd.year'
751 #)
752
753 $source = $schema->resultset('CD')->source;
754 @columns = $source->resolve_prefetch( qw[/ artist producer /] );
755
756 # @columns =
757 #(
758 # 'artist.artistid',
759 # 'artist.name',
760 # 'producer.producerid',
761 # 'producer.name'
75d07914 762 #)
988bf309 763
b3e8ac9b 764=cut
765
766sub resolve_prefetch {
0f66a01b 767 my ($self, $pre, $alias, $seen, $order, $collapse) = @_;
489709af 768 $seen ||= {};
b3e8ac9b 769 #$alias ||= $self->name;
770 #warn $alias, Dumper $pre;
771 if( ref $pre eq 'ARRAY' ) {
0f66a01b 772 return
773 map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) }
774 @$pre;
b3e8ac9b 775 }
776 elsif( ref $pre eq 'HASH' ) {
777 my @ret =
778 map {
0f66a01b 779 $self->resolve_prefetch($_, $alias, $seen, $order, $collapse),
489709af 780 $self->related_source($_)->resolve_prefetch(
0f66a01b 781 $pre->{$_}, "${alias}.$_", $seen, $order, $collapse)
782 } keys %$pre;
b3e8ac9b 783 #die Dumper \@ret;
784 return @ret;
785 }
786 elsif( ref $pre ) {
a86b1efe 787 $self->throw_exception(
788 "don't know how to resolve prefetch reftype ".ref($pre));
b3e8ac9b 789 }
790 else {
489709af 791 my $count = ++$seen->{$pre};
792 my $as = ($count > 1 ? "${pre}_${count}" : $pre);
b3e8ac9b 793 my $rel_info = $self->relationship_info( $pre );
a86b1efe 794 $self->throw_exception( $self->name . " has no such relationship '$pre'" )
795 unless $rel_info;
37f23589 796 my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
a86b1efe 797 my $rel_source = $self->related_source($pre);
0f66a01b 798
799 if (exists $rel_info->{attrs}{accessor}
800 && $rel_info->{attrs}{accessor} eq 'multi') {
801 $self->throw_exception(
802 "Can't prefetch has_many ${pre} (join cond too complex)")
803 unless ref($rel_info->{cond}) eq 'HASH';
37f23589 804 my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
0f66a01b 805 keys %{$rel_info->{cond}};
806 $collapse->{"${as_prefix}${pre}"} = \@key;
5a5bec6c 807 my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
808 ? @{$rel_info->{attrs}{order_by}}
809 : (defined $rel_info->{attrs}{order_by}
810 ? ($rel_info->{attrs}{order_by})
811 : ()));
812 push(@$order, map { "${as}.$_" } (@key, @ord));
0f66a01b 813 }
814
489709af 815 return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
a86b1efe 816 $rel_source->columns;
b3e8ac9b 817 #warn $alias, Dumper (\@ret);
489709af 818 #return @ret;
b3e8ac9b 819 }
820}
953a18ef 821
87c4e602 822=head2 related_source
823
27f01d1f 824=over 4
825
ebc77b53 826=item Arguments: $relname
27f01d1f 827
828=back
87772e46 829
2053ab2a 830Returns the result source object for the given relationship.
87772e46 831
832=cut
833
834sub related_source {
835 my ($self, $rel) = @_;
aea52c85 836 if( !$self->has_relationship( $rel ) ) {
701da8c4 837 $self->throw_exception("No such relationship '$rel'");
aea52c85 838 }
87772e46 839 return $self->schema->source($self->relationship_info($rel)->{source});
8452e496 840}
841
77254782 842=head2 related_class
843
27f01d1f 844=over 4
845
ebc77b53 846=item Arguments: $relname
27f01d1f 847
848=back
77254782 849
2053ab2a 850Returns the class name for objects in the given relationship.
77254782 851
852=cut
853
854sub related_class {
855 my ($self, $rel) = @_;
856 if( !$self->has_relationship( $rel ) ) {
857 $self->throw_exception("No such relationship '$rel'");
858 }
859 return $self->schema->class($self->relationship_info($rel)->{source});
860}
861
5ac6a044 862=head2 resultset
863
bcc5a210 864Returns a resultset for the given source. This will initially be created
865on demand by calling
5ac6a044 866
988bf309 867 $self->resultset_class->new($self, $self->resultset_attributes)
5ac6a044 868
bcc5a210 869but is cached from then on unless resultset_class changes.
870
5ac6a044 871=head2 resultset_class
872
988bf309 873Set the class of the resultset, this is useful if you want to create your
874own resultset methods. Create your own class derived from
875L<DBIx::Class::ResultSet>, and set it here.
5ac6a044 876
877=head2 resultset_attributes
878
988bf309 879Specify here any attributes you wish to pass to your specialised resultset.
5ac6a044 880
881=cut
882
883sub resultset {
884 my $self = shift;
27f01d1f 885 $self->throw_exception(
886 'resultset does not take any arguments. If you want another resultset, '.
887 'call it on the schema instead.'
888 ) if scalar @_;
428c2b82 889
890 # disabled until we can figure out a way to do it without consistency issues
891 #
892 #return $self->{_resultset}
893 # if ref $self->{_resultset} eq $self->resultset_class;
894 #return $self->{_resultset} =
895
896 return $self->resultset_class->new(
27f01d1f 897 $self, $self->{resultset_attributes}
898 );
5ac6a044 899}
900
bab77431 901=head2 source_name
902
903=over 4
904
905=item Arguments: $source_name
906
907=back
908
909Set the name of the result source when it is loaded into a schema.
910This is usefull if you want to refer to a result source by a name other than
911its class name.
912
913 package ArchivedBooks;
914 use base qw/DBIx::Class/;
915 __PACKAGE__->table('books_archive');
916 __PACKAGE__->source_name('Books');
917
918 # from your schema...
919 $schema->resultset('Books')->find(1);
920
701da8c4 921=head2 throw_exception
922
2053ab2a 923See L<DBIx::Class::Schema/"throw_exception">.
701da8c4 924
925=cut
926
927sub throw_exception {
928 my $self = shift;
75d07914 929 if (defined $self->schema) {
701da8c4 930 $self->schema->throw_exception(@_);
931 } else {
932 croak(@_);
933 }
934}
935
9c992ba1 936=head1 AUTHORS
937
938Matt S. Trout <mst@shadowcatsystems.co.uk>
939
940=head1 LICENSE
941
942You may distribute this code under the same terms as Perl itself.
943
944=cut
945