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