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