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