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