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