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