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