fixed a stupid typo
[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
210=head3 Arguments: (@cols)
87f0da6a 211
9c992ba1 212Defines one or more columns as primary key for this source. Should be
213called after C<add_columns>.
87f0da6a 214
215Additionally, defines a unique constraint named C<primary>.
216
988bf309 217The primary key columns are used by L<DBIx::Class::PK::Auto> to
218retrieve automatically created values from the database.
219
87f0da6a 220=cut
9c992ba1 221
222sub set_primary_key {
223 my ($self, @cols) = @_;
224 # check if primary key columns are valid columns
8e04bf91 225 foreach my $col (@cols) {
226 $self->throw_exception("No such column $col on table " . $self->name)
227 unless $self->has_column($col);
9c992ba1 228 }
229 $self->_primaries(\@cols);
87f0da6a 230
231 $self->add_unique_constraint(primary => \@cols);
9c992ba1 232}
233
87f0da6a 234=head2 primary_columns
235
9c992ba1 236Read-only accessor which returns the list of primary keys.
30126ac7 237
87f0da6a 238=cut
9c992ba1 239
240sub primary_columns {
241 return @{shift->_primaries||[]};
242}
243
87f0da6a 244=head2 add_unique_constraint
245
246Declare a unique constraint on this source. Call once for each unique
988bf309 247constraint. Unique constraints are used when you call C<find> on a
958916aa 248L<DBIx::Class::ResultSet>, only columns in the constraint are searched,
87f0da6a 249
250 # For e.g. UNIQUE (column1, column2)
251 __PACKAGE__->add_unique_constraint(constraint_name => [ qw/column1 column2/ ]);
252
253=cut
254
255sub add_unique_constraint {
256 my ($self, $name, $cols) = @_;
257
8e04bf91 258 foreach my $col (@$cols) {
259 $self->throw_exception("No such column $col on table " . $self->name)
260 unless $self->has_column($col);
87f0da6a 261 }
262
263 my %unique_constraints = $self->unique_constraints;
264 $unique_constraints{$name} = $cols;
265 $self->_unique_constraints(\%unique_constraints);
266}
267
268=head2 unique_constraints
269
270Read-only accessor which returns the list of unique constraints on this source.
271
272=cut
273
274sub unique_constraints {
275 return %{shift->_unique_constraints||{}};
276}
277
9c992ba1 278=head2 from
279
280Returns an expression of the source to be supplied to storage to specify
281retrieval from this source; in the case of a database the required FROM clause
282contents.
283
284=cut
285
286=head2 storage
287
988bf309 288Returns the storage handle for the current schema.
289
290See also: L<DBIx::Class::Storage>
9c992ba1 291
292=cut
293
294sub storage { shift->schema->storage; }
295
8452e496 296=head2 add_relationship
297
298 $source->add_relationship('relname', 'related_source', $cond, $attrs);
299
24d67825 300The relationship name can be arbitrary, but must be unique for each
301relationship attached to this result source. 'related_source' should
302be the name with which the related result source was registered with
303the current schema. For example:
8452e496 304
24d67825 305 $schema->source('Book')->add_relationship('reviews', 'Review', {
306 'foreign.book_id' => 'self.id',
307 });
308
309The condition C<$cond> needs to be an SQL::Abstract-style
310representation of the join between the tables. For example, if you're
311creating a rel from Author to Book,
988bf309 312
313 { 'foreign.author_id' => 'self.id' }
314
315will result in the JOIN clause
316
317 author me JOIN book foreign ON foreign.author_id = me.id
318
8452e496 319You can specify as many foreign => self mappings as necessary.
320
988bf309 321Valid attributes are as follows:
322
323=over 4
324
325=item join_type
326
327Explicitly specifies the type of join to use in the relationship. Any
328SQL join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in
329the SQL command immediately before C<JOIN>.
330
331=item proxy
332
24d67825 333An arrayref containing a list of accessors in the foreign class to proxy in
334the main class. If, for example, you do the following:
335
336 CD->might_have(liner_notes => 'LinerNotes', undef, {
337 proxy => [ qw/notes/ ],
338 });
339
340Then, assuming LinerNotes has an accessor named notes, you can do:
988bf309 341
24d67825 342 my $cd = CD->find(1);
343 $cd->notes('Notes go here'); # set notes -- LinerNotes object is
344 # created if it doesn't exist
988bf309 345
346=item accessor
347
348Specifies the type of accessor that should be created for the
349relationship. Valid values are C<single> (for when there is only a single
350related object), C<multi> (when there can be many), and C<filter> (for
351when there is a single related object, but you also want the relationship
352accessor to double as a column accessor). For C<multi> accessors, an
353add_to_* method is also created, which calls C<create_related> for the
354relationship.
355
8452e496 356=back
357
358=cut
359
360sub add_relationship {
361 my ($self, $rel, $f_source_name, $cond, $attrs) = @_;
701da8c4 362 $self->throw_exception("Can't create relationship without join condition") unless $cond;
8452e496 363 $attrs ||= {};
87772e46 364
8452e496 365 my %rels = %{ $self->_relationships };
366 $rels{$rel} = { class => $f_source_name,
87772e46 367 source => $f_source_name,
8452e496 368 cond => $cond,
369 attrs => $attrs };
370 $self->_relationships(\%rels);
371
30126ac7 372 return $self;
87772e46 373
953a18ef 374 # XXX disabled. doesn't work properly currently. skip in tests.
375
8452e496 376 my $f_source = $self->schema->source($f_source_name);
377 unless ($f_source) {
378 eval "require $f_source_name;";
379 if ($@) {
380 die $@ unless $@ =~ /Can't locate/;
381 }
382 $f_source = $f_source_name->result_source;
87772e46 383 #my $s_class = ref($self->schema);
384 #$f_source_name =~ m/^${s_class}::(.*)$/;
385 #$self->schema->register_class(($1 || $f_source_name), $f_source_name);
386 #$f_source = $self->schema->source($f_source_name);
8452e496 387 }
388 return unless $f_source; # Can't test rel without f_source
389
390 eval { $self->resolve_join($rel, 'me') };
391
392 if ($@) { # If the resolve failed, back out and re-throw the error
393 delete $rels{$rel}; #
394 $self->_relationships(\%rels);
701da8c4 395 $self->throw_exception("Error creating relationship $rel: $@");
8452e496 396 }
397 1;
398}
399
87c4e602 400=head2 relationships
8452e496 401
402Returns all valid relationship names for this source
403
404=cut
405
406sub relationships {
407 return keys %{shift->_relationships};
408}
409
87c4e602 410=head2 relationship_info
411
412=head3 Arguments: ($relname)
8452e496 413
414Returns the relationship information for the specified relationship name
415
416=cut
417
418sub relationship_info {
419 my ($self, $rel) = @_;
420 return $self->_relationships->{$rel};
421}
422
87c4e602 423=head2 has_relationship
424
425=head3 Arguments: ($rel)
953a18ef 426
427Returns 1 if the source has a relationship of this name, 0 otherwise.
988bf309 428
429=cut
953a18ef 430
431sub has_relationship {
432 my ($self, $rel) = @_;
433 return exists $self->_relationships->{$rel};
434}
435
87c4e602 436=head2 resolve_join
437
438=head3 Arguments: ($relation)
8452e496 439
440Returns the join structure required for the related result source
441
442=cut
443
444sub resolve_join {
489709af 445 my ($self, $join, $alias, $seen) = @_;
446 $seen ||= {};
87772e46 447 if (ref $join eq 'ARRAY') {
489709af 448 return map { $self->resolve_join($_, $alias, $seen) } @$join;
87772e46 449 } elsif (ref $join eq 'HASH') {
489709af 450 return
887ce227 451 map {
452 my $as = ($seen->{$_} ? $_.'_'.($seen->{$_}+1) : $_);
453 ($self->resolve_join($_, $alias, $seen),
454 $self->related_source($_)->resolve_join($join->{$_}, $as, $seen));
455 } keys %$join;
87772e46 456 } elsif (ref $join) {
701da8c4 457 $self->throw_exception("No idea how to resolve join reftype ".ref $join);
87772e46 458 } else {
489709af 459 my $count = ++$seen->{$join};
460 #use Data::Dumper; warn Dumper($seen);
461 my $as = ($count > 1 ? "${join}_${count}" : $join);
3842b955 462 my $rel_info = $self->relationship_info($join);
701da8c4 463 $self->throw_exception("No such relationship ${join}") unless $rel_info;
3842b955 464 my $type = $rel_info->{attrs}{join_type} || '';
489709af 465 return [ { $as => $self->related_source($join)->from,
953a18ef 466 -join_type => $type },
489709af 467 $self->resolve_condition($rel_info->{cond}, $as, $alias) ];
953a18ef 468 }
469}
470
87c4e602 471=head2 resolve_condition
472
473=head3 Arguments: ($cond, $as, $alias|$object)
953a18ef 474
3842b955 475Resolves the passed condition to a concrete query fragment. If given an alias,
953a18ef 476returns a join condition; if given an object, inverts that object to produce
477a related conditional from that object.
478
479=cut
480
481sub resolve_condition {
489709af 482 my ($self, $cond, $as, $for) = @_;
953a18ef 483 #warn %$cond;
484 if (ref $cond eq 'HASH') {
485 my %ret;
486 while (my ($k, $v) = each %{$cond}) {
487 # XXX should probably check these are valid columns
701da8c4 488 $k =~ s/^foreign\.// || $self->throw_exception("Invalid rel cond key ${k}");
489 $v =~ s/^self\.// || $self->throw_exception("Invalid rel cond val ${v}");
953a18ef 490 if (ref $for) { # Object
3842b955 491 #warn "$self $k $for $v";
492 $ret{$k} = $for->get_column($v);
493 #warn %ret;
fde6e28e 494 } elsif (ref $as) { # reverse object
495 $ret{$v} = $as->get_column($k);
953a18ef 496 } else {
489709af 497 $ret{"${as}.${k}"} = "${for}.${v}";
953a18ef 498 }
953a18ef 499 }
500 return \%ret;
5efe4c79 501 } elsif (ref $cond eq 'ARRAY') {
489709af 502 return [ map { $self->resolve_condition($_, $as, $for) } @$cond ];
953a18ef 503 } else {
504 die("Can't handle this yet :(");
87772e46 505 }
506}
507
87c4e602 508=head2 resolve_prefetch
509
510=head3 Arguments: (hashref/arrayref/scalar)
988bf309 511
b3e8ac9b 512Accepts one or more relationships for the current source and returns an
513array of column names for each of those relationships. Column names are
514prefixed relative to the current source, in accordance with where they appear
515in the supplied relationships. Examples:
516
5ac6a044 517 my $source = $schema->resultset('Tag')->source;
b3e8ac9b 518 @columns = $source->resolve_prefetch( { cd => 'artist' } );
519
520 # @columns =
521 #(
522 # 'cd.cdid',
523 # 'cd.artist',
524 # 'cd.title',
525 # 'cd.year',
526 # 'cd.artist.artistid',
527 # 'cd.artist.name'
528 #)
529
530 @columns = $source->resolve_prefetch( qw[/ cd /] );
531
532 # @columns =
533 #(
534 # 'cd.cdid',
535 # 'cd.artist',
536 # 'cd.title',
537 # 'cd.year'
538 #)
539
540 $source = $schema->resultset('CD')->source;
541 @columns = $source->resolve_prefetch( qw[/ artist producer /] );
542
543 # @columns =
544 #(
545 # 'artist.artistid',
546 # 'artist.name',
547 # 'producer.producerid',
548 # 'producer.name'
549 #)
988bf309 550
b3e8ac9b 551=cut
552
553sub resolve_prefetch {
0f66a01b 554 my ($self, $pre, $alias, $seen, $order, $collapse) = @_;
489709af 555 $seen ||= {};
b3e8ac9b 556 #$alias ||= $self->name;
557 #warn $alias, Dumper $pre;
558 if( ref $pre eq 'ARRAY' ) {
0f66a01b 559 return
560 map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) }
561 @$pre;
b3e8ac9b 562 }
563 elsif( ref $pre eq 'HASH' ) {
564 my @ret =
565 map {
0f66a01b 566 $self->resolve_prefetch($_, $alias, $seen, $order, $collapse),
489709af 567 $self->related_source($_)->resolve_prefetch(
0f66a01b 568 $pre->{$_}, "${alias}.$_", $seen, $order, $collapse)
569 } keys %$pre;
b3e8ac9b 570 #die Dumper \@ret;
571 return @ret;
572 }
573 elsif( ref $pre ) {
a86b1efe 574 $self->throw_exception(
575 "don't know how to resolve prefetch reftype ".ref($pre));
b3e8ac9b 576 }
577 else {
489709af 578 my $count = ++$seen->{$pre};
579 my $as = ($count > 1 ? "${pre}_${count}" : $pre);
b3e8ac9b 580 my $rel_info = $self->relationship_info( $pre );
a86b1efe 581 $self->throw_exception( $self->name . " has no such relationship '$pre'" )
582 unless $rel_info;
37f23589 583 my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
a86b1efe 584 my $rel_source = $self->related_source($pre);
0f66a01b 585
586 if (exists $rel_info->{attrs}{accessor}
587 && $rel_info->{attrs}{accessor} eq 'multi') {
588 $self->throw_exception(
589 "Can't prefetch has_many ${pre} (join cond too complex)")
590 unless ref($rel_info->{cond}) eq 'HASH';
37f23589 591 my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
0f66a01b 592 keys %{$rel_info->{cond}};
593 $collapse->{"${as_prefix}${pre}"} = \@key;
5a5bec6c 594 my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
595 ? @{$rel_info->{attrs}{order_by}}
596 : (defined $rel_info->{attrs}{order_by}
597 ? ($rel_info->{attrs}{order_by})
598 : ()));
599 push(@$order, map { "${as}.$_" } (@key, @ord));
0f66a01b 600 }
601
489709af 602 return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
a86b1efe 603 $rel_source->columns;
b3e8ac9b 604 #warn $alias, Dumper (\@ret);
489709af 605 #return @ret;
b3e8ac9b 606 }
607}
953a18ef 608
87c4e602 609=head2 related_source
610
611=head3 Arguments: ($relname)
87772e46 612
988bf309 613Returns the result source object for the given relationship
87772e46 614
615=cut
616
617sub related_source {
618 my ($self, $rel) = @_;
aea52c85 619 if( !$self->has_relationship( $rel ) ) {
701da8c4 620 $self->throw_exception("No such relationship '$rel'");
aea52c85 621 }
87772e46 622 return $self->schema->source($self->relationship_info($rel)->{source});
8452e496 623}
624
77254782 625=head2 related_class
626
627=head3 Arguments: ($relname)
628
629Returns the class object for the given relationship
630
631=cut
632
633sub related_class {
634 my ($self, $rel) = @_;
635 if( !$self->has_relationship( $rel ) ) {
636 $self->throw_exception("No such relationship '$rel'");
637 }
638 return $self->schema->class($self->relationship_info($rel)->{source});
639}
640
5ac6a044 641=head2 resultset
642
bcc5a210 643Returns a resultset for the given source. This will initially be created
644on demand by calling
5ac6a044 645
988bf309 646 $self->resultset_class->new($self, $self->resultset_attributes)
5ac6a044 647
bcc5a210 648but is cached from then on unless resultset_class changes.
649
5ac6a044 650=head2 resultset_class
651
988bf309 652Set the class of the resultset, this is useful if you want to create your
653own resultset methods. Create your own class derived from
654L<DBIx::Class::ResultSet>, and set it here.
5ac6a044 655
656=head2 resultset_attributes
657
988bf309 658Specify here any attributes you wish to pass to your specialised resultset.
5ac6a044 659
660=cut
661
662sub resultset {
663 my $self = shift;
e0f56292 664 $self->throw_exception('resultset does not take any arguments. If you want another resultset, call it on the schema instead.') if scalar @_;
1225fc4d 665 return $self->{_resultset} if ref $self->{_resultset} eq $self->resultset_class;
bcd26419 666 return $self->{_resultset} = $self->resultset_class->new($self, $self->{resultset_attributes});
5ac6a044 667}
668
701da8c4 669=head2 throw_exception
670
988bf309 671See throw_exception in L<DBIx::Class::Schema>.
701da8c4 672
673=cut
674
675sub throw_exception {
676 my $self = shift;
677 if (defined $self->schema) {
678 $self->schema->throw_exception(@_);
679 } else {
680 croak(@_);
681 }
682}
683
684
9c992ba1 685=head1 AUTHORS
686
687Matt S. Trout <mst@shadowcatsystems.co.uk>
688
689=head1 LICENSE
690
691You may distribute this code under the same terms as Perl itself.
692
693=cut
694