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