Doc updates in DBIx/Class.pm
[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
296The relation name can be arbitrary, but must be unique for each relationship
297attached to this result source. 'related_source' should be the name with
298which the related result source was registered with the current schema
299(for simple schemas this is usally either Some::Namespace::Foo or just Foo)
300
301The condition needs to be an SQL::Abstract-style representation of the join
988bf309 302between the tables. For example, if you're creating a rel from Author to Book,
303
304 { 'foreign.author_id' => 'self.id' }
305
306will result in the JOIN clause
307
308 author me JOIN book foreign ON foreign.author_id = me.id
309
8452e496 310You can specify as many foreign => self mappings as necessary.
311
988bf309 312Valid attributes are as follows:
313
314=over 4
315
316=item join_type
317
318Explicitly specifies the type of join to use in the relationship. Any
319SQL join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in
320the SQL command immediately before C<JOIN>.
321
322=item proxy
323
324An arrayref containing a list of accessors in the foreign class to
325proxy in the main class. If, for example, you do the following:
326
327 __PACKAGE__->might_have(bar => 'Bar', undef, { proxy => [ qw/margle/] });
328
329Then, assuming Bar has an accessor named margle, you can do:
330
331 my $obj = Foo->find(1);
332 $obj->margle(10); # set margle; Bar object is created if it doesn't exist
333
334=item accessor
335
336Specifies the type of accessor that should be created for the
337relationship. Valid values are C<single> (for when there is only a single
338related object), C<multi> (when there can be many), and C<filter> (for
339when there is a single related object, but you also want the relationship
340accessor to double as a column accessor). For C<multi> accessors, an
341add_to_* method is also created, which calls C<create_related> for the
342relationship.
343
8452e496 344=back
345
346=cut
347
348sub add_relationship {
349 my ($self, $rel, $f_source_name, $cond, $attrs) = @_;
701da8c4 350 $self->throw_exception("Can't create relationship without join condition") unless $cond;
8452e496 351 $attrs ||= {};
87772e46 352
8452e496 353 my %rels = %{ $self->_relationships };
354 $rels{$rel} = { class => $f_source_name,
87772e46 355 source => $f_source_name,
8452e496 356 cond => $cond,
357 attrs => $attrs };
358 $self->_relationships(\%rels);
359
30126ac7 360 return $self;
87772e46 361
953a18ef 362 # XXX disabled. doesn't work properly currently. skip in tests.
363
8452e496 364 my $f_source = $self->schema->source($f_source_name);
365 unless ($f_source) {
366 eval "require $f_source_name;";
367 if ($@) {
368 die $@ unless $@ =~ /Can't locate/;
369 }
370 $f_source = $f_source_name->result_source;
87772e46 371 #my $s_class = ref($self->schema);
372 #$f_source_name =~ m/^${s_class}::(.*)$/;
373 #$self->schema->register_class(($1 || $f_source_name), $f_source_name);
374 #$f_source = $self->schema->source($f_source_name);
8452e496 375 }
376 return unless $f_source; # Can't test rel without f_source
377
378 eval { $self->resolve_join($rel, 'me') };
379
380 if ($@) { # If the resolve failed, back out and re-throw the error
381 delete $rels{$rel}; #
382 $self->_relationships(\%rels);
701da8c4 383 $self->throw_exception("Error creating relationship $rel: $@");
8452e496 384 }
385 1;
386}
387
87c4e602 388=head2 relationships
8452e496 389
390Returns all valid relationship names for this source
391
392=cut
393
394sub relationships {
395 return keys %{shift->_relationships};
396}
397
87c4e602 398=head2 relationship_info
399
400=head3 Arguments: ($relname)
8452e496 401
402Returns the relationship information for the specified relationship name
403
404=cut
405
406sub relationship_info {
407 my ($self, $rel) = @_;
408 return $self->_relationships->{$rel};
409}
410
87c4e602 411=head2 has_relationship
412
413=head3 Arguments: ($rel)
953a18ef 414
415Returns 1 if the source has a relationship of this name, 0 otherwise.
988bf309 416
417=cut
953a18ef 418
419sub has_relationship {
420 my ($self, $rel) = @_;
421 return exists $self->_relationships->{$rel};
422}
423
87c4e602 424=head2 resolve_join
425
426=head3 Arguments: ($relation)
8452e496 427
428Returns the join structure required for the related result source
429
430=cut
431
432sub resolve_join {
489709af 433 my ($self, $join, $alias, $seen) = @_;
434 $seen ||= {};
87772e46 435 if (ref $join eq 'ARRAY') {
489709af 436 return map { $self->resolve_join($_, $alias, $seen) } @$join;
87772e46 437 } elsif (ref $join eq 'HASH') {
489709af 438 return
887ce227 439 map {
440 my $as = ($seen->{$_} ? $_.'_'.($seen->{$_}+1) : $_);
441 ($self->resolve_join($_, $alias, $seen),
442 $self->related_source($_)->resolve_join($join->{$_}, $as, $seen));
443 } keys %$join;
87772e46 444 } elsif (ref $join) {
701da8c4 445 $self->throw_exception("No idea how to resolve join reftype ".ref $join);
87772e46 446 } else {
489709af 447 my $count = ++$seen->{$join};
448 #use Data::Dumper; warn Dumper($seen);
449 my $as = ($count > 1 ? "${join}_${count}" : $join);
3842b955 450 my $rel_info = $self->relationship_info($join);
701da8c4 451 $self->throw_exception("No such relationship ${join}") unless $rel_info;
3842b955 452 my $type = $rel_info->{attrs}{join_type} || '';
489709af 453 return [ { $as => $self->related_source($join)->from,
953a18ef 454 -join_type => $type },
489709af 455 $self->resolve_condition($rel_info->{cond}, $as, $alias) ];
953a18ef 456 }
457}
458
87c4e602 459=head2 resolve_condition
460
461=head3 Arguments: ($cond, $as, $alias|$object)
953a18ef 462
3842b955 463Resolves the passed condition to a concrete query fragment. If given an alias,
953a18ef 464returns a join condition; if given an object, inverts that object to produce
465a related conditional from that object.
466
467=cut
468
469sub resolve_condition {
489709af 470 my ($self, $cond, $as, $for) = @_;
953a18ef 471 #warn %$cond;
472 if (ref $cond eq 'HASH') {
473 my %ret;
474 while (my ($k, $v) = each %{$cond}) {
475 # XXX should probably check these are valid columns
701da8c4 476 $k =~ s/^foreign\.// || $self->throw_exception("Invalid rel cond key ${k}");
477 $v =~ s/^self\.// || $self->throw_exception("Invalid rel cond val ${v}");
953a18ef 478 if (ref $for) { # Object
3842b955 479 #warn "$self $k $for $v";
480 $ret{$k} = $for->get_column($v);
481 #warn %ret;
fde6e28e 482 } elsif (ref $as) { # reverse object
483 $ret{$v} = $as->get_column($k);
953a18ef 484 } else {
489709af 485 $ret{"${as}.${k}"} = "${for}.${v}";
953a18ef 486 }
953a18ef 487 }
488 return \%ret;
5efe4c79 489 } elsif (ref $cond eq 'ARRAY') {
489709af 490 return [ map { $self->resolve_condition($_, $as, $for) } @$cond ];
953a18ef 491 } else {
492 die("Can't handle this yet :(");
87772e46 493 }
494}
495
87c4e602 496=head2 resolve_prefetch
497
498=head3 Arguments: (hashref/arrayref/scalar)
988bf309 499
b3e8ac9b 500Accepts one or more relationships for the current source and returns an
501array of column names for each of those relationships. Column names are
502prefixed relative to the current source, in accordance with where they appear
503in the supplied relationships. Examples:
504
5ac6a044 505 my $source = $schema->resultset('Tag')->source;
b3e8ac9b 506 @columns = $source->resolve_prefetch( { cd => 'artist' } );
507
508 # @columns =
509 #(
510 # 'cd.cdid',
511 # 'cd.artist',
512 # 'cd.title',
513 # 'cd.year',
514 # 'cd.artist.artistid',
515 # 'cd.artist.name'
516 #)
517
518 @columns = $source->resolve_prefetch( qw[/ cd /] );
519
520 # @columns =
521 #(
522 # 'cd.cdid',
523 # 'cd.artist',
524 # 'cd.title',
525 # 'cd.year'
526 #)
527
528 $source = $schema->resultset('CD')->source;
529 @columns = $source->resolve_prefetch( qw[/ artist producer /] );
530
531 # @columns =
532 #(
533 # 'artist.artistid',
534 # 'artist.name',
535 # 'producer.producerid',
536 # 'producer.name'
537 #)
988bf309 538
b3e8ac9b 539=cut
540
541sub resolve_prefetch {
0f66a01b 542 my ($self, $pre, $alias, $seen, $order, $collapse) = @_;
489709af 543 $seen ||= {};
b3e8ac9b 544 #$alias ||= $self->name;
545 #warn $alias, Dumper $pre;
546 if( ref $pre eq 'ARRAY' ) {
0f66a01b 547 return
548 map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) }
549 @$pre;
b3e8ac9b 550 }
551 elsif( ref $pre eq 'HASH' ) {
552 my @ret =
553 map {
0f66a01b 554 $self->resolve_prefetch($_, $alias, $seen, $order, $collapse),
489709af 555 $self->related_source($_)->resolve_prefetch(
0f66a01b 556 $pre->{$_}, "${alias}.$_", $seen, $order, $collapse)
557 } keys %$pre;
b3e8ac9b 558 #die Dumper \@ret;
559 return @ret;
560 }
561 elsif( ref $pre ) {
a86b1efe 562 $self->throw_exception(
563 "don't know how to resolve prefetch reftype ".ref($pre));
b3e8ac9b 564 }
565 else {
489709af 566 my $count = ++$seen->{$pre};
567 my $as = ($count > 1 ? "${pre}_${count}" : $pre);
b3e8ac9b 568 my $rel_info = $self->relationship_info( $pre );
a86b1efe 569 $self->throw_exception( $self->name . " has no such relationship '$pre'" )
570 unless $rel_info;
37f23589 571 my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
a86b1efe 572 my $rel_source = $self->related_source($pre);
0f66a01b 573
574 if (exists $rel_info->{attrs}{accessor}
575 && $rel_info->{attrs}{accessor} eq 'multi') {
576 $self->throw_exception(
577 "Can't prefetch has_many ${pre} (join cond too complex)")
578 unless ref($rel_info->{cond}) eq 'HASH';
37f23589 579 my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
0f66a01b 580 keys %{$rel_info->{cond}};
581 $collapse->{"${as_prefix}${pre}"} = \@key;
5a5bec6c 582 my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
583 ? @{$rel_info->{attrs}{order_by}}
584 : (defined $rel_info->{attrs}{order_by}
585 ? ($rel_info->{attrs}{order_by})
586 : ()));
587 push(@$order, map { "${as}.$_" } (@key, @ord));
0f66a01b 588 }
589
489709af 590 return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
a86b1efe 591 $rel_source->columns;
b3e8ac9b 592 #warn $alias, Dumper (\@ret);
489709af 593 #return @ret;
b3e8ac9b 594 }
595}
953a18ef 596
87c4e602 597=head2 related_source
598
599=head3 Arguments: ($relname)
87772e46 600
988bf309 601Returns the result source object for the given relationship
87772e46 602
603=cut
604
605sub related_source {
606 my ($self, $rel) = @_;
aea52c85 607 if( !$self->has_relationship( $rel ) ) {
701da8c4 608 $self->throw_exception("No such relationship '$rel'");
aea52c85 609 }
87772e46 610 return $self->schema->source($self->relationship_info($rel)->{source});
8452e496 611}
612
5ac6a044 613=head2 resultset
614
988bf309 615Returns a resultset for the given source, by calling:
5ac6a044 616
988bf309 617 $self->resultset_class->new($self, $self->resultset_attributes)
5ac6a044 618
619=head2 resultset_class
620
988bf309 621Set the class of the resultset, this is useful if you want to create your
622own resultset methods. Create your own class derived from
623L<DBIx::Class::ResultSet>, and set it here.
5ac6a044 624
625=head2 resultset_attributes
626
988bf309 627Specify here any attributes you wish to pass to your specialised resultset.
5ac6a044 628
629=cut
630
631sub resultset {
632 my $self = shift;
e0f56292 633 $self->throw_exception('resultset does not take any arguments. If you want another resultset, call it on the schema instead.') if scalar @_;
1225fc4d 634 return $self->{_resultset} if ref $self->{_resultset} eq $self->resultset_class;
bcd26419 635 return $self->{_resultset} = $self->resultset_class->new($self, $self->{resultset_attributes});
5ac6a044 636}
637
701da8c4 638=head2 throw_exception
639
988bf309 640See throw_exception in L<DBIx::Class::Schema>.
701da8c4 641
642=cut
643
644sub throw_exception {
645 my $self = shift;
646 if (defined $self->schema) {
647 $self->schema->throw_exception(@_);
648 } else {
649 croak(@_);
650 }
651}
652
653
9c992ba1 654=head1 AUTHORS
655
656Matt S. Trout <mst@shadowcatsystems.co.uk>
657
658=head1 LICENSE
659
660You may distribute this code under the same terms as Perl itself.
661
662=cut
663