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