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