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