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