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