0.06000 changes
[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;
701da8c4 7use Carp::Clan qw/^DBIx::Class/;
6da5894c 8use Storable;
9
9c992ba1 10use base qw/DBIx::Class/;
11__PACKAGE__->load_components(qw/AccessorGroup/);
12
aa1088bf 13__PACKAGE__->mk_group_accessors('simple' => qw/_ordered_columns
14 _columns _primaries _unique_constraints name resultset_attributes
15 schema from _relationships/);
16
17__PACKAGE__->mk_group_accessors('component_class' => qw/resultset_class
18 result_class/);
9c992ba1 19
20=head1 NAME
21
22DBIx::Class::ResultSource - Result source object
23
24=head1 SYNOPSIS
25
26=head1 DESCRIPTION
27
28A ResultSource is a component of a schema from which results can be directly
29retrieved, most usually a table (see L<DBIx::Class::ResultSource::Table>)
30
31=head1 METHODS
32
33=cut
34
35sub new {
36 my ($class, $attrs) = @_;
37 $class = ref $class if ref $class;
1225fc4d 38 my $new = bless({ %{$attrs || {}}, _resultset => undef }, $class);
9c992ba1 39 $new->{resultset_class} ||= 'DBIx::Class::ResultSet';
5ac6a044 40 $new->{resultset_attributes} = { %{$new->{resultset_attributes} || {}} };
6da5894c 41 $new->{_ordered_columns} = [ @{$new->{_ordered_columns}||[]}];
42 $new->{_columns} = { %{$new->{_columns}||{}} };
43 $new->{_relationships} = { %{$new->{_relationships}||{}} };
9c992ba1 44 $new->{name} ||= "!!NAME NOT SET!!";
5afa2a15 45 $new->{_columns_info_loaded} ||= 0;
9c992ba1 46 return $new;
47}
48
988bf309 49=pod
50
5ac6a044 51=head2 add_columns
52
53 $table->add_columns(qw/col1 col2 col3/);
54
55 $table->add_columns('col1' => \%col1_info, 'col2' => \%col2_info, ...);
56
57Adds columns to the result source. If supplied key => hashref pairs uses
58the hashref as the column_info for that column.
59
988bf309 60Repeated calls of this method will add more columns, not replace them.
61
62The contents of the column_info are not set in stone, the following
63keys are currently recognised/used by DBIx::Class.
64
65=over 4
66
67=item accessor
68
69Use this to set the name of the accessor for this column. If unset,
70the name of the column will be used.
71
72=item data_type
73
74This contains the column type, it is automatically filled by the
75L<SQL::Translator::Producer::DBIx::Class::File> producer, and the
76L<DBIx::Class::Schema::Loader> module. If you do not enter the
77data_type, DBIx::Class will attempt to retrieve it from the
78database for you, using L<DBI>s column_info method. The values of this
79key are typically upper-cased.
80
81Currently there is no standard set of values for the data_type, use
82whatever your database(s) support.
83
84=item size
85
86The length of your column, if it is a column type that can have a size
87restriction. This is currently not used by DBIx::Class.
88
89=item is_nullable
90
91If the column is allowed to contain NULL values, set a true value
92(typically 1), here. This is currently not used by DBIx::Class.
93
94=item is_auto_increment
95
96Set this to a true value if this is a column that is somehow
e666492c 97automatically filled. This is used to determine which columns to empty
98when cloning objects using C<copy>.
988bf309 99
100=item is_foreign_key
101
102Set this to a true value if this column represents a key from a
103foreign table. This is currently not used by DBIx::Class.
104
105=item default_value
106
107Set this to the default value which will be inserted into this column
108by the database. Can contain either values or functions. This is
109currently not used by DBIx::Class.
110
111=item sequence
112
318a6210 113Sets the name of the sequence to use to generate values. If not
114specified, L<DBIx::Class::PK::Auto> will attempt to retrieve the
115name of the sequence from the database automatically.
988bf309 116
117=back
118
5ac6a044 119=head2 add_column
120
121 $table->add_column('col' => \%info?);
122
123Convenience alias to add_columns
124
125=cut
126
9c992ba1 127sub add_columns {
128 my ($self, @cols) = @_;
8e04bf91 129 $self->_ordered_columns(\@cols) unless $self->_ordered_columns;
130
20518cb4 131 my @added;
132 my $columns = $self->_columns;
9c992ba1 133 while (my $col = shift @cols) {
8e04bf91 134 # If next entry is { ... } use that for the column info, if not
135 # use an empty hashref
30126ac7 136 my $column_info = ref $cols[0] ? shift(@cols) : {};
20518cb4 137 push(@added, $col) unless exists $columns->{$col};
20518cb4 138 $columns->{$col} = $column_info;
9c992ba1 139 }
20518cb4 140 push @{ $self->_ordered_columns }, @added;
30126ac7 141 return $self;
9c992ba1 142}
143
144*add_column = \&add_columns;
145
3842b955 146=head2 has_column
147
988bf309 148 if ($obj->has_column($col)) { ... }
149
9c992ba1 150Returns 1 if the source has a column of this name, 0 otherwise.
988bf309 151
152=cut
9c992ba1 153
154sub has_column {
155 my ($self, $column) = @_;
156 return exists $self->_columns->{$column};
157}
158
87c4e602 159=head2 column_info
9c992ba1 160
988bf309 161 my $info = $obj->column_info($col);
9c992ba1 162
988bf309 163Returns the column metadata hashref for a column. See the description
164of add_column for information on the contents of the hashref.
9c992ba1 165
988bf309 166=cut
9c992ba1 167
168sub column_info {
169 my ($self, $column) = @_;
701da8c4 170 $self->throw_exception("No such column $column")
171 unless exists $self->_columns->{$column};
5afa2a15 172 #warn $self->{_columns_info_loaded}, "\n";
8e04bf91 173 if ( ! $self->_columns->{$column}{data_type}
174 and ! $self->{_columns_info_loaded}
175 and $self->schema and $self->storage )
176 {
177 $self->{_columns_info_loaded}++;
178 my $info;
179 # eval for the case of storage without table
180 eval { $info = $self->storage->columns_info_for($self->from) };
181 unless ($@) {
182 foreach my $col ( keys %{$self->_columns} ) {
183 foreach my $i ( keys %{$info->{$col}} ) {
184 $self->_columns->{$col}{$i} = $info->{$col}{$i};
185 }
a953d8d9 186 }
8e04bf91 187 }
a953d8d9 188 }
9c992ba1 189 return $self->_columns->{$column};
190}
191
192=head2 columns
193
20518cb4 194 my @column_names = $obj->columns;
195
196Returns all column names in the order they were declared to add_columns
87f0da6a 197
198=cut
9c992ba1 199
200sub columns {
8e04bf91 201 my $self = shift;
aa1088bf 202 $self->throw_exception(
203 "columns() is a read-only accessor, did you mean add_columns()?"
204 ) if (@_ > 1);
701da8c4 205 return @{$self->{_ordered_columns}||[]};
571dced3 206}
207
87c4e602 208=head2 set_primary_key
209
27f01d1f 210=over 4
211
ebc77b53 212=item Arguments: @cols
27f01d1f 213
214=back
87f0da6a 215
9c992ba1 216Defines one or more columns as primary key for this source. Should be
217called after C<add_columns>.
87f0da6a 218
219Additionally, defines a unique constraint named C<primary>.
220
988bf309 221The primary key columns are used by L<DBIx::Class::PK::Auto> to
222retrieve automatically created values from the database.
223
87f0da6a 224=cut
9c992ba1 225
226sub set_primary_key {
227 my ($self, @cols) = @_;
228 # check if primary key columns are valid columns
8e04bf91 229 foreach my $col (@cols) {
230 $self->throw_exception("No such column $col on table " . $self->name)
231 unless $self->has_column($col);
9c992ba1 232 }
233 $self->_primaries(\@cols);
87f0da6a 234
235 $self->add_unique_constraint(primary => \@cols);
9c992ba1 236}
237
87f0da6a 238=head2 primary_columns
239
9c992ba1 240Read-only accessor which returns the list of primary keys.
30126ac7 241
87f0da6a 242=cut
9c992ba1 243
244sub primary_columns {
245 return @{shift->_primaries||[]};
246}
247
87f0da6a 248=head2 add_unique_constraint
249
250Declare a unique constraint on this source. Call once for each unique
988bf309 251constraint. Unique constraints are used when you call C<find> on a
958916aa 252L<DBIx::Class::ResultSet>, only columns in the constraint are searched,
87f0da6a 253
27f01d1f 254e.g.,
255
256 # For UNIQUE (column1, column2)
257 __PACKAGE__->add_unique_constraint(
258 constraint_name => [ qw/column1 column2/ ],
259 );
87f0da6a 260
261=cut
262
263sub add_unique_constraint {
264 my ($self, $name, $cols) = @_;
265
8e04bf91 266 foreach my $col (@$cols) {
267 $self->throw_exception("No such column $col on table " . $self->name)
268 unless $self->has_column($col);
87f0da6a 269 }
270
271 my %unique_constraints = $self->unique_constraints;
272 $unique_constraints{$name} = $cols;
273 $self->_unique_constraints(\%unique_constraints);
274}
275
276=head2 unique_constraints
277
278Read-only accessor which returns the list of unique constraints on this source.
279
280=cut
281
282sub unique_constraints {
283 return %{shift->_unique_constraints||{}};
284}
285
9c992ba1 286=head2 from
287
288Returns an expression of the source to be supplied to storage to specify
289retrieval from this source; in the case of a database the required FROM clause
290contents.
291
292=cut
293
294=head2 storage
295
988bf309 296Returns the storage handle for the current schema.
297
298See also: L<DBIx::Class::Storage>
9c992ba1 299
300=cut
301
302sub storage { shift->schema->storage; }
303
8452e496 304=head2 add_relationship
305
306 $source->add_relationship('relname', 'related_source', $cond, $attrs);
307
24d67825 308The relationship name can be arbitrary, but must be unique for each
309relationship attached to this result source. 'related_source' should
310be the name with which the related result source was registered with
311the current schema. For example:
8452e496 312
24d67825 313 $schema->source('Book')->add_relationship('reviews', 'Review', {
314 'foreign.book_id' => 'self.id',
315 });
316
317The condition C<$cond> needs to be an SQL::Abstract-style
318representation of the join between the tables. For example, if you're
319creating a rel from Author to Book,
988bf309 320
321 { 'foreign.author_id' => 'self.id' }
322
323will result in the JOIN clause
324
325 author me JOIN book foreign ON foreign.author_id = me.id
326
8452e496 327You can specify as many foreign => self mappings as necessary.
328
988bf309 329Valid attributes are as follows:
330
331=over 4
332
333=item join_type
334
335Explicitly specifies the type of join to use in the relationship. Any
336SQL join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in
337the SQL command immediately before C<JOIN>.
338
339=item proxy
340
24d67825 341An arrayref containing a list of accessors in the foreign class to proxy in
342the main class. If, for example, you do the following:
343
344 CD->might_have(liner_notes => 'LinerNotes', undef, {
345 proxy => [ qw/notes/ ],
346 });
347
348Then, assuming LinerNotes has an accessor named notes, you can do:
988bf309 349
24d67825 350 my $cd = CD->find(1);
351 $cd->notes('Notes go here'); # set notes -- LinerNotes object is
352 # created if it doesn't exist
988bf309 353
354=item accessor
355
356Specifies the type of accessor that should be created for the
357relationship. Valid values are C<single> (for when there is only a single
358related object), C<multi> (when there can be many), and C<filter> (for
359when there is a single related object, but you also want the relationship
360accessor to double as a column accessor). For C<multi> accessors, an
361add_to_* method is also created, which calls C<create_related> for the
362relationship.
363
8452e496 364=back
365
366=cut
367
368sub add_relationship {
369 my ($self, $rel, $f_source_name, $cond, $attrs) = @_;
27f01d1f 370 $self->throw_exception("Can't create relationship without join condition")
371 unless $cond;
8452e496 372 $attrs ||= {};
87772e46 373
8452e496 374 my %rels = %{ $self->_relationships };
375 $rels{$rel} = { class => $f_source_name,
87772e46 376 source => $f_source_name,
8452e496 377 cond => $cond,
378 attrs => $attrs };
379 $self->_relationships(\%rels);
380
30126ac7 381 return $self;
87772e46 382
953a18ef 383 # XXX disabled. doesn't work properly currently. skip in tests.
384
8452e496 385 my $f_source = $self->schema->source($f_source_name);
386 unless ($f_source) {
387 eval "require $f_source_name;";
388 if ($@) {
389 die $@ unless $@ =~ /Can't locate/;
390 }
391 $f_source = $f_source_name->result_source;
87772e46 392 #my $s_class = ref($self->schema);
393 #$f_source_name =~ m/^${s_class}::(.*)$/;
394 #$self->schema->register_class(($1 || $f_source_name), $f_source_name);
395 #$f_source = $self->schema->source($f_source_name);
8452e496 396 }
397 return unless $f_source; # Can't test rel without f_source
398
399 eval { $self->resolve_join($rel, 'me') };
400
401 if ($@) { # If the resolve failed, back out and re-throw the error
402 delete $rels{$rel}; #
403 $self->_relationships(\%rels);
701da8c4 404 $self->throw_exception("Error creating relationship $rel: $@");
8452e496 405 }
406 1;
407}
408
87c4e602 409=head2 relationships
8452e496 410
411Returns all valid relationship names for this source
412
413=cut
414
415sub relationships {
416 return keys %{shift->_relationships};
417}
418
87c4e602 419=head2 relationship_info
420
27f01d1f 421=over 4
422
ebc77b53 423=item Arguments: $relname
27f01d1f 424
425=back
8452e496 426
427Returns the relationship information for the specified relationship name
428
429=cut
430
431sub relationship_info {
432 my ($self, $rel) = @_;
433 return $self->_relationships->{$rel};
434}
435
87c4e602 436=head2 has_relationship
437
27f01d1f 438=over 4
439
ebc77b53 440=item Arguments: $rel
27f01d1f 441
442=back
953a18ef 443
444Returns 1 if the source has a relationship of this name, 0 otherwise.
988bf309 445
446=cut
953a18ef 447
448sub has_relationship {
449 my ($self, $rel) = @_;
450 return exists $self->_relationships->{$rel};
451}
452
87c4e602 453=head2 resolve_join
454
27f01d1f 455=over 4
456
ebc77b53 457=item Arguments: $relation
27f01d1f 458
459=back
8452e496 460
461Returns the join structure required for the related result source
462
463=cut
464
465sub resolve_join {
489709af 466 my ($self, $join, $alias, $seen) = @_;
467 $seen ||= {};
87772e46 468 if (ref $join eq 'ARRAY') {
489709af 469 return map { $self->resolve_join($_, $alias, $seen) } @$join;
87772e46 470 } elsif (ref $join eq 'HASH') {
489709af 471 return
887ce227 472 map {
473 my $as = ($seen->{$_} ? $_.'_'.($seen->{$_}+1) : $_);
474 ($self->resolve_join($_, $alias, $seen),
475 $self->related_source($_)->resolve_join($join->{$_}, $as, $seen));
476 } keys %$join;
87772e46 477 } elsif (ref $join) {
701da8c4 478 $self->throw_exception("No idea how to resolve join reftype ".ref $join);
87772e46 479 } else {
489709af 480 my $count = ++$seen->{$join};
481 #use Data::Dumper; warn Dumper($seen);
482 my $as = ($count > 1 ? "${join}_${count}" : $join);
3842b955 483 my $rel_info = $self->relationship_info($join);
701da8c4 484 $self->throw_exception("No such relationship ${join}") unless $rel_info;
3842b955 485 my $type = $rel_info->{attrs}{join_type} || '';
489709af 486 return [ { $as => $self->related_source($join)->from,
953a18ef 487 -join_type => $type },
489709af 488 $self->resolve_condition($rel_info->{cond}, $as, $alias) ];
953a18ef 489 }
490}
491
87c4e602 492=head2 resolve_condition
493
27f01d1f 494=over 4
495
ebc77b53 496=item Arguments: $cond, $as, $alias|$object
27f01d1f 497
498=back
953a18ef 499
3842b955 500Resolves the passed condition to a concrete query fragment. If given an alias,
953a18ef 501returns a join condition; if given an object, inverts that object to produce
502a related conditional from that object.
503
504=cut
505
506sub resolve_condition {
489709af 507 my ($self, $cond, $as, $for) = @_;
953a18ef 508 #warn %$cond;
509 if (ref $cond eq 'HASH') {
510 my %ret;
511 while (my ($k, $v) = each %{$cond}) {
512 # XXX should probably check these are valid columns
27f01d1f 513 $k =~ s/^foreign\.// ||
514 $self->throw_exception("Invalid rel cond key ${k}");
515 $v =~ s/^self\.// ||
516 $self->throw_exception("Invalid rel cond val ${v}");
953a18ef 517 if (ref $for) { # Object
3842b955 518 #warn "$self $k $for $v";
519 $ret{$k} = $for->get_column($v);
520 #warn %ret;
fde6e28e 521 } elsif (ref $as) { # reverse object
522 $ret{$v} = $as->get_column($k);
953a18ef 523 } else {
489709af 524 $ret{"${as}.${k}"} = "${for}.${v}";
953a18ef 525 }
953a18ef 526 }
527 return \%ret;
5efe4c79 528 } elsif (ref $cond eq 'ARRAY') {
489709af 529 return [ map { $self->resolve_condition($_, $as, $for) } @$cond ];
953a18ef 530 } else {
531 die("Can't handle this yet :(");
87772e46 532 }
533}
534
87c4e602 535=head2 resolve_prefetch
536
27f01d1f 537=over 4
538
ebc77b53 539=item Arguments: hashref/arrayref/scalar
27f01d1f 540
541=back
988bf309 542
b3e8ac9b 543Accepts one or more relationships for the current source and returns an
544array of column names for each of those relationships. Column names are
545prefixed relative to the current source, in accordance with where they appear
546in the supplied relationships. Examples:
547
5ac6a044 548 my $source = $schema->resultset('Tag')->source;
b3e8ac9b 549 @columns = $source->resolve_prefetch( { cd => 'artist' } );
550
551 # @columns =
552 #(
553 # 'cd.cdid',
554 # 'cd.artist',
555 # 'cd.title',
556 # 'cd.year',
557 # 'cd.artist.artistid',
558 # 'cd.artist.name'
559 #)
560
561 @columns = $source->resolve_prefetch( qw[/ cd /] );
562
563 # @columns =
564 #(
565 # 'cd.cdid',
566 # 'cd.artist',
567 # 'cd.title',
568 # 'cd.year'
569 #)
570
571 $source = $schema->resultset('CD')->source;
572 @columns = $source->resolve_prefetch( qw[/ artist producer /] );
573
574 # @columns =
575 #(
576 # 'artist.artistid',
577 # 'artist.name',
578 # 'producer.producerid',
579 # 'producer.name'
580 #)
988bf309 581
b3e8ac9b 582=cut
583
584sub resolve_prefetch {
0f66a01b 585 my ($self, $pre, $alias, $seen, $order, $collapse) = @_;
489709af 586 $seen ||= {};
b3e8ac9b 587 #$alias ||= $self->name;
588 #warn $alias, Dumper $pre;
589 if( ref $pre eq 'ARRAY' ) {
0f66a01b 590 return
591 map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) }
592 @$pre;
b3e8ac9b 593 }
594 elsif( ref $pre eq 'HASH' ) {
595 my @ret =
596 map {
0f66a01b 597 $self->resolve_prefetch($_, $alias, $seen, $order, $collapse),
489709af 598 $self->related_source($_)->resolve_prefetch(
0f66a01b 599 $pre->{$_}, "${alias}.$_", $seen, $order, $collapse)
600 } keys %$pre;
b3e8ac9b 601 #die Dumper \@ret;
602 return @ret;
603 }
604 elsif( ref $pre ) {
a86b1efe 605 $self->throw_exception(
606 "don't know how to resolve prefetch reftype ".ref($pre));
b3e8ac9b 607 }
608 else {
489709af 609 my $count = ++$seen->{$pre};
610 my $as = ($count > 1 ? "${pre}_${count}" : $pre);
b3e8ac9b 611 my $rel_info = $self->relationship_info( $pre );
a86b1efe 612 $self->throw_exception( $self->name . " has no such relationship '$pre'" )
613 unless $rel_info;
37f23589 614 my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
a86b1efe 615 my $rel_source = $self->related_source($pre);
0f66a01b 616
617 if (exists $rel_info->{attrs}{accessor}
618 && $rel_info->{attrs}{accessor} eq 'multi') {
619 $self->throw_exception(
620 "Can't prefetch has_many ${pre} (join cond too complex)")
621 unless ref($rel_info->{cond}) eq 'HASH';
37f23589 622 my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
0f66a01b 623 keys %{$rel_info->{cond}};
624 $collapse->{"${as_prefix}${pre}"} = \@key;
5a5bec6c 625 my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
626 ? @{$rel_info->{attrs}{order_by}}
627 : (defined $rel_info->{attrs}{order_by}
628 ? ($rel_info->{attrs}{order_by})
629 : ()));
630 push(@$order, map { "${as}.$_" } (@key, @ord));
0f66a01b 631 }
632
489709af 633 return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
a86b1efe 634 $rel_source->columns;
b3e8ac9b 635 #warn $alias, Dumper (\@ret);
489709af 636 #return @ret;
b3e8ac9b 637 }
638}
953a18ef 639
87c4e602 640=head2 related_source
641
27f01d1f 642=over 4
643
ebc77b53 644=item Arguments: $relname
27f01d1f 645
646=back
87772e46 647
988bf309 648Returns the result source object for the given relationship
87772e46 649
650=cut
651
652sub related_source {
653 my ($self, $rel) = @_;
aea52c85 654 if( !$self->has_relationship( $rel ) ) {
701da8c4 655 $self->throw_exception("No such relationship '$rel'");
aea52c85 656 }
87772e46 657 return $self->schema->source($self->relationship_info($rel)->{source});
8452e496 658}
659
77254782 660=head2 related_class
661
27f01d1f 662=over 4
663
ebc77b53 664=item Arguments: $relname
27f01d1f 665
666=back
77254782 667
668Returns the class object for the given relationship
669
670=cut
671
672sub related_class {
673 my ($self, $rel) = @_;
674 if( !$self->has_relationship( $rel ) ) {
675 $self->throw_exception("No such relationship '$rel'");
676 }
677 return $self->schema->class($self->relationship_info($rel)->{source});
678}
679
5ac6a044 680=head2 resultset
681
bcc5a210 682Returns a resultset for the given source. This will initially be created
683on demand by calling
5ac6a044 684
988bf309 685 $self->resultset_class->new($self, $self->resultset_attributes)
5ac6a044 686
bcc5a210 687but is cached from then on unless resultset_class changes.
688
5ac6a044 689=head2 resultset_class
690
988bf309 691Set the class of the resultset, this is useful if you want to create your
692own resultset methods. Create your own class derived from
693L<DBIx::Class::ResultSet>, and set it here.
5ac6a044 694
695=head2 resultset_attributes
696
988bf309 697Specify here any attributes you wish to pass to your specialised resultset.
5ac6a044 698
699=cut
700
701sub resultset {
702 my $self = shift;
27f01d1f 703 $self->throw_exception(
704 'resultset does not take any arguments. If you want another resultset, '.
705 'call it on the schema instead.'
706 ) if scalar @_;
707 return $self->{_resultset}
708 if ref $self->{_resultset} eq $self->resultset_class;
709 return $self->{_resultset} = $self->resultset_class->new(
710 $self, $self->{resultset_attributes}
711 );
5ac6a044 712}
713
701da8c4 714=head2 throw_exception
715
988bf309 716See throw_exception in L<DBIx::Class::Schema>.
701da8c4 717
718=cut
719
720sub throw_exception {
721 my $self = shift;
722 if (defined $self->schema) {
723 $self->schema->throw_exception(@_);
724 } else {
725 croak(@_);
726 }
727}
728
729
9c992ba1 730=head1 AUTHORS
731
732Matt S. Trout <mst@shadowcatsystems.co.uk>
733
734=head1 LICENSE
735
736You may distribute this code under the same terms as Perl itself.
737
738=cut
739