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