Add more about accessors to doc
[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
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
8452e496 522 my %rels = %{ $self->_relationships };
523 $rels{$rel} = { class => $f_source_name,
87772e46 524 source => $f_source_name,
8452e496 525 cond => $cond,
526 attrs => $attrs };
527 $self->_relationships(\%rels);
528
30126ac7 529 return $self;
87772e46 530
953a18ef 531 # XXX disabled. doesn't work properly currently. skip in tests.
532
8452e496 533 my $f_source = $self->schema->source($f_source_name);
534 unless ($f_source) {
c037c03a 535 $self->ensure_class_loaded($f_source_name);
8452e496 536 $f_source = $f_source_name->result_source;
87772e46 537 #my $s_class = ref($self->schema);
538 #$f_source_name =~ m/^${s_class}::(.*)$/;
539 #$self->schema->register_class(($1 || $f_source_name), $f_source_name);
540 #$f_source = $self->schema->source($f_source_name);
8452e496 541 }
542 return unless $f_source; # Can't test rel without f_source
543
544 eval { $self->resolve_join($rel, 'me') };
545
546 if ($@) { # If the resolve failed, back out and re-throw the error
75d07914 547 delete $rels{$rel}; #
8452e496 548 $self->_relationships(\%rels);
701da8c4 549 $self->throw_exception("Error creating relationship $rel: $@");
8452e496 550 }
551 1;
552}
553
87c4e602 554=head2 relationships
8452e496 555
2053ab2a 556Returns all relationship names for this source.
8452e496 557
558=cut
559
560sub relationships {
561 return keys %{shift->_relationships};
562}
563
87c4e602 564=head2 relationship_info
565
27f01d1f 566=over 4
567
ebc77b53 568=item Arguments: $relname
27f01d1f 569
570=back
8452e496 571
2053ab2a 572Returns a hash of relationship information for the specified relationship
573name.
8452e496 574
575=cut
576
577sub relationship_info {
578 my ($self, $rel) = @_;
579 return $self->_relationships->{$rel};
75d07914 580}
8452e496 581
87c4e602 582=head2 has_relationship
583
27f01d1f 584=over 4
585
ebc77b53 586=item Arguments: $rel
27f01d1f 587
588=back
953a18ef 589
2053ab2a 590Returns true if the source has a relationship of this name, false otherwise.
988bf309 591
592=cut
953a18ef 593
594sub has_relationship {
595 my ($self, $rel) = @_;
596 return exists $self->_relationships->{$rel};
597}
598
de60a93d 599=head2 reverse_relationship_info
600
601=over 4
602
603=item Arguments: $relname
604
605=back
606
bab77431 607Returns an array of hash references of relationship information for
de60a93d 608the other side of the specified relationship name.
609
610=cut
611
612sub reverse_relationship_info {
613 my ($self, $rel) = @_;
614 my $rel_info = $self->relationship_info($rel);
615 my $ret = {};
616
617 return $ret unless ((ref $rel_info->{cond}) eq 'HASH');
618
619 my @cond = keys(%{$rel_info->{cond}});
620 my @refkeys = map {/^\w+\.(\w+)$/} @cond;
621 my @keys = map {$rel_info->{cond}->{$_} =~ /^\w+\.(\w+)$/} @cond;
bab77431 622
de60a93d 623 # Get the related result source for this relationship
624 my $othertable = $self->related_source($rel);
625
626 # Get all the relationships for that source that related to this source
627 # whose foreign column set are our self columns on $rel and whose self
bab77431 628 # columns are our foreign columns on $rel.
de60a93d 629 my @otherrels = $othertable->relationships();
630 my $otherrelationship;
631 foreach my $otherrel (@otherrels) {
632 my $otherrel_info = $othertable->relationship_info($otherrel);
633
634 my $back = $othertable->related_source($otherrel);
635 next unless $back->name eq $self->name;
636
637 my @othertestconds;
638
639 if (ref $otherrel_info->{cond} eq 'HASH') {
640 @othertestconds = ($otherrel_info->{cond});
641 }
642 elsif (ref $otherrel_info->{cond} eq 'ARRAY') {
643 @othertestconds = @{$otherrel_info->{cond}};
644 }
645 else {
646 next;
647 }
648
649 foreach my $othercond (@othertestconds) {
650 my @other_cond = keys(%$othercond);
651 my @other_refkeys = map {/^\w+\.(\w+)$/} @other_cond;
652 my @other_keys = map {$othercond->{$_} =~ /^\w+\.(\w+)$/} @other_cond;
bab77431 653 next if (!$self->compare_relationship_keys(\@refkeys, \@other_keys) ||
de60a93d 654 !$self->compare_relationship_keys(\@other_refkeys, \@keys));
655 $ret->{$otherrel} = $otherrel_info;
656 }
657 }
658 return $ret;
659}
660
661=head2 compare_relationship_keys
662
663=over 4
664
665=item Arguments: $keys1, $keys2
666
667=back
668
669Returns true if both sets of keynames are the same, false otherwise.
670
671=cut
672
673sub compare_relationship_keys {
674 my ($self, $keys1, $keys2) = @_;
675
676 # Make sure every keys1 is in keys2
677 my $found;
678 foreach my $key (@$keys1) {
679 $found = 0;
680 foreach my $prim (@$keys2) {
681 if ($prim eq $key) {
682 $found = 1;
683 last;
684 }
685 }
686 last unless $found;
687 }
688
689 # Make sure every key2 is in key1
690 if ($found) {
691 foreach my $prim (@$keys2) {
692 $found = 0;
693 foreach my $key (@$keys1) {
694 if ($prim eq $key) {
695 $found = 1;
696 last;
697 }
698 }
699 last unless $found;
700 }
701 }
702
703 return $found;
704}
705
87c4e602 706=head2 resolve_join
707
27f01d1f 708=over 4
709
ebc77b53 710=item Arguments: $relation
27f01d1f 711
712=back
8452e496 713
2053ab2a 714Returns the join structure required for the related result source.
8452e496 715
716=cut
717
718sub resolve_join {
24010dd8 719 my ($self, $join, $alias, $seen, $force_left) = @_;
489709af 720 $seen ||= {};
24010dd8 721 $force_left ||= { force => 0 };
87772e46 722 if (ref $join eq 'ARRAY') {
489709af 723 return map { $self->resolve_join($_, $alias, $seen) } @$join;
87772e46 724 } elsif (ref $join eq 'HASH') {
489709af 725 return
887ce227 726 map {
727 my $as = ($seen->{$_} ? $_.'_'.($seen->{$_}+1) : $_);
24010dd8 728 local $force_left->{force};
729 (
730 $self->resolve_join($_, $alias, $seen, $force_left),
731 $self->related_source($_)->resolve_join(
732 $join->{$_}, $as, $seen, $force_left
733 )
734 );
887ce227 735 } keys %$join;
87772e46 736 } elsif (ref $join) {
701da8c4 737 $self->throw_exception("No idea how to resolve join reftype ".ref $join);
87772e46 738 } else {
489709af 739 my $count = ++$seen->{$join};
740 #use Data::Dumper; warn Dumper($seen);
741 my $as = ($count > 1 ? "${join}_${count}" : $join);
3842b955 742 my $rel_info = $self->relationship_info($join);
701da8c4 743 $self->throw_exception("No such relationship ${join}") unless $rel_info;
24010dd8 744 my $type;
745 if ($force_left->{force}) {
746 $type = 'left';
747 } else {
748 $type = $rel_info->{attrs}{join_type} || '';
749 $force_left->{force} = 1 if lc($type) eq 'left';
750 }
489709af 751 return [ { $as => $self->related_source($join)->from,
953a18ef 752 -join_type => $type },
489709af 753 $self->resolve_condition($rel_info->{cond}, $as, $alias) ];
953a18ef 754 }
755}
756
87c4e602 757=head2 resolve_condition
758
27f01d1f 759=over 4
760
ebc77b53 761=item Arguments: $cond, $as, $alias|$object
27f01d1f 762
763=back
953a18ef 764
3842b955 765Resolves the passed condition to a concrete query fragment. If given an alias,
953a18ef 766returns a join condition; if given an object, inverts that object to produce
767a related conditional from that object.
768
769=cut
770
771sub resolve_condition {
489709af 772 my ($self, $cond, $as, $for) = @_;
953a18ef 773 #warn %$cond;
774 if (ref $cond eq 'HASH') {
775 my %ret;
bd054cb4 776 foreach my $k (keys %{$cond}) {
777 my $v = $cond->{$k};
953a18ef 778 # XXX should probably check these are valid columns
27f01d1f 779 $k =~ s/^foreign\.// ||
75d07914 780 $self->throw_exception("Invalid rel cond key ${k}");
27f01d1f 781 $v =~ s/^self\.// ||
75d07914 782 $self->throw_exception("Invalid rel cond val ${v}");
953a18ef 783 if (ref $for) { # Object
3842b955 784 #warn "$self $k $for $v";
785 $ret{$k} = $for->get_column($v);
786 #warn %ret;
2c037e6b 787 } elsif (!defined $for) { # undef, i.e. "no object"
788 $ret{$k} = undef;
2ec8e594 789 } elsif (ref $as eq 'HASH') { # reverse hashref
790 $ret{$v} = $as->{$k};
fde6e28e 791 } elsif (ref $as) { # reverse object
792 $ret{$v} = $as->get_column($k);
2c037e6b 793 } elsif (!defined $as) { # undef, i.e. "no reverse object"
794 $ret{$v} = undef;
953a18ef 795 } else {
489709af 796 $ret{"${as}.${k}"} = "${for}.${v}";
953a18ef 797 }
953a18ef 798 }
799 return \%ret;
5efe4c79 800 } elsif (ref $cond eq 'ARRAY') {
489709af 801 return [ map { $self->resolve_condition($_, $as, $for) } @$cond ];
953a18ef 802 } else {
803 die("Can't handle this yet :(");
87772e46 804 }
805}
806
87c4e602 807=head2 resolve_prefetch
808
27f01d1f 809=over 4
810
ebc77b53 811=item Arguments: hashref/arrayref/scalar
27f01d1f 812
813=back
988bf309 814
b3e8ac9b 815Accepts one or more relationships for the current source and returns an
816array of column names for each of those relationships. Column names are
817prefixed relative to the current source, in accordance with where they appear
818in the supplied relationships. Examples:
819
5ac6a044 820 my $source = $schema->resultset('Tag')->source;
b3e8ac9b 821 @columns = $source->resolve_prefetch( { cd => 'artist' } );
822
823 # @columns =
824 #(
825 # 'cd.cdid',
826 # 'cd.artist',
827 # 'cd.title',
828 # 'cd.year',
829 # 'cd.artist.artistid',
830 # 'cd.artist.name'
831 #)
832
833 @columns = $source->resolve_prefetch( qw[/ cd /] );
834
835 # @columns =
836 #(
837 # 'cd.cdid',
838 # 'cd.artist',
839 # 'cd.title',
840 # 'cd.year'
841 #)
842
843 $source = $schema->resultset('CD')->source;
844 @columns = $source->resolve_prefetch( qw[/ artist producer /] );
845
846 # @columns =
847 #(
848 # 'artist.artistid',
849 # 'artist.name',
850 # 'producer.producerid',
851 # 'producer.name'
75d07914 852 #)
988bf309 853
b3e8ac9b 854=cut
855
856sub resolve_prefetch {
0f66a01b 857 my ($self, $pre, $alias, $seen, $order, $collapse) = @_;
489709af 858 $seen ||= {};
b3e8ac9b 859 #$alias ||= $self->name;
860 #warn $alias, Dumper $pre;
861 if( ref $pre eq 'ARRAY' ) {
0f66a01b 862 return
863 map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) }
864 @$pre;
b3e8ac9b 865 }
866 elsif( ref $pre eq 'HASH' ) {
867 my @ret =
868 map {
0f66a01b 869 $self->resolve_prefetch($_, $alias, $seen, $order, $collapse),
489709af 870 $self->related_source($_)->resolve_prefetch(
0f66a01b 871 $pre->{$_}, "${alias}.$_", $seen, $order, $collapse)
872 } keys %$pre;
b3e8ac9b 873 #die Dumper \@ret;
874 return @ret;
875 }
876 elsif( ref $pre ) {
a86b1efe 877 $self->throw_exception(
878 "don't know how to resolve prefetch reftype ".ref($pre));
b3e8ac9b 879 }
880 else {
489709af 881 my $count = ++$seen->{$pre};
882 my $as = ($count > 1 ? "${pre}_${count}" : $pre);
b3e8ac9b 883 my $rel_info = $self->relationship_info( $pre );
a86b1efe 884 $self->throw_exception( $self->name . " has no such relationship '$pre'" )
885 unless $rel_info;
37f23589 886 my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
a86b1efe 887 my $rel_source = $self->related_source($pre);
0f66a01b 888
889 if (exists $rel_info->{attrs}{accessor}
890 && $rel_info->{attrs}{accessor} eq 'multi') {
891 $self->throw_exception(
892 "Can't prefetch has_many ${pre} (join cond too complex)")
893 unless ref($rel_info->{cond}) eq 'HASH';
b25e9fa0 894 #my @col = map { (/^self\.(.+)$/ ? ("${as_prefix}.$1") : ()); }
895 # values %{$rel_info->{cond}};
896 $collapse->{".${as_prefix}${pre}"} = [ $rel_source->primary_columns ];
897 # action at a distance. prepending the '.' allows simpler code
898 # in ResultSet->_collapse_result
37f23589 899 my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
0f66a01b 900 keys %{$rel_info->{cond}};
5a5bec6c 901 my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
902 ? @{$rel_info->{attrs}{order_by}}
903 : (defined $rel_info->{attrs}{order_by}
904 ? ($rel_info->{attrs}{order_by})
905 : ()));
906 push(@$order, map { "${as}.$_" } (@key, @ord));
0f66a01b 907 }
908
489709af 909 return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
a86b1efe 910 $rel_source->columns;
b3e8ac9b 911 #warn $alias, Dumper (\@ret);
489709af 912 #return @ret;
b3e8ac9b 913 }
914}
953a18ef 915
87c4e602 916=head2 related_source
917
27f01d1f 918=over 4
919
ebc77b53 920=item Arguments: $relname
27f01d1f 921
922=back
87772e46 923
2053ab2a 924Returns the result source object for the given relationship.
87772e46 925
926=cut
927
928sub related_source {
929 my ($self, $rel) = @_;
aea52c85 930 if( !$self->has_relationship( $rel ) ) {
701da8c4 931 $self->throw_exception("No such relationship '$rel'");
aea52c85 932 }
87772e46 933 return $self->schema->source($self->relationship_info($rel)->{source});
8452e496 934}
935
77254782 936=head2 related_class
937
27f01d1f 938=over 4
939
ebc77b53 940=item Arguments: $relname
27f01d1f 941
942=back
77254782 943
2053ab2a 944Returns the class name for objects in the given relationship.
77254782 945
946=cut
947
948sub related_class {
949 my ($self, $rel) = @_;
950 if( !$self->has_relationship( $rel ) ) {
951 $self->throw_exception("No such relationship '$rel'");
952 }
953 return $self->schema->class($self->relationship_info($rel)->{source});
954}
955
5ac6a044 956=head2 resultset
957
bcc5a210 958Returns a resultset for the given source. This will initially be created
959on demand by calling
5ac6a044 960
988bf309 961 $self->resultset_class->new($self, $self->resultset_attributes)
5ac6a044 962
bcc5a210 963but is cached from then on unless resultset_class changes.
964
5ac6a044 965=head2 resultset_class
966
d7be2784 967` package My::ResultSetClass;
968 use base 'DBIx::Class::ResultSet';
969 ...
970
971 $source->resultset_class('My::ResultSet::Class');
972
988bf309 973Set the class of the resultset, this is useful if you want to create your
974own resultset methods. Create your own class derived from
d7be2784 975L<DBIx::Class::ResultSet>, and set it here.
5ac6a044 976
977=head2 resultset_attributes
978
d7be2784 979 $source->resultset_attributes({ order_by => [ 'id' ] });
980
d84c7d78 981Specify here any attributes you wish to pass to your specialised
982resultset. For a full list of these, please see
983L<DBIx::Class::ResultSet/ATTRIBUTES>.
5ac6a044 984
985=cut
986
987sub resultset {
988 my $self = shift;
27f01d1f 989 $self->throw_exception(
990 'resultset does not take any arguments. If you want another resultset, '.
991 'call it on the schema instead.'
992 ) if scalar @_;
428c2b82 993
428c2b82 994 return $self->resultset_class->new(
e6c747fd 995 $self,
996 {
997 %{$self->{resultset_attributes}},
998 %{$self->schema->default_resultset_attributes}
999 },
27f01d1f 1000 );
5ac6a044 1001}
1002
bab77431 1003=head2 source_name
1004
1005=over 4
1006
1007=item Arguments: $source_name
1008
1009=back
1010
1011Set the name of the result source when it is loaded into a schema.
1012This is usefull if you want to refer to a result source by a name other than
1013its class name.
1014
1015 package ArchivedBooks;
1016 use base qw/DBIx::Class/;
1017 __PACKAGE__->table('books_archive');
1018 __PACKAGE__->source_name('Books');
1019
1020 # from your schema...
1021 $schema->resultset('Books')->find(1);
1022
aec3eff1 1023=head2 handle
1024
1025Obtain a new handle to this source. Returns an instance of a
1026L<DBIx::Class::ResultSourceHandle>.
1027
1028=cut
1029
1030sub handle {
1031 return new DBIx::Class::ResultSourceHandle({
1032 schema => $_[0]->schema,
3441fd57 1033 source_moniker => $_[0]->source_name
aec3eff1 1034 });
1035}
1036
701da8c4 1037=head2 throw_exception
1038
2053ab2a 1039See L<DBIx::Class::Schema/"throw_exception">.
701da8c4 1040
1041=cut
1042
1043sub throw_exception {
1044 my $self = shift;
75d07914 1045 if (defined $self->schema) {
701da8c4 1046 $self->schema->throw_exception(@_);
1047 } else {
1048 croak(@_);
1049 }
1050}
1051
9c992ba1 1052=head1 AUTHORS
1053
1054Matt S. Trout <mst@shadowcatsystems.co.uk>
1055
1056=head1 LICENSE
1057
1058You may distribute this code under the same terms as Perl itself.
1059
1060=cut
1061
b25e9fa0 10621;