rewrite of _collapse_result to support prefetch of multiple has_many
[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;
aec3eff1 7use DBIx::Class::ResultSourceHandle;
701da8c4 8use Carp::Clan qw/^DBIx::Class/;
6da5894c 9use Storable;
10
9c992ba1 11use base qw/DBIx::Class/;
9c992ba1 12
aa1088bf 13__PACKAGE__->mk_group_accessors('simple' => qw/_ordered_columns
14 _columns _primaries _unique_constraints name resultset_attributes
acbe81cf 15 schema from _relationships column_info_from_storage source_info
f89bb832 16 source_name sqlt_deploy_callback/);
aa1088bf 17
fac560c2 18__PACKAGE__->mk_group_accessors('component_class' => qw/resultset_class
b0dd0e03 19 result_class/);
9c992ba1 20
75d07914 21=head1 NAME
9c992ba1 22
23DBIx::Class::ResultSource - Result source object
24
25=head1 SYNOPSIS
26
16ccb4fe 27 # Create a table based result source, in a result class.
28
29 package MyDB::Schema::Result::Artist;
30 use base qw/DBIx::Class/;
31
32 __PACKAGE__->load_components(qw/Core/);
33 __PACKAGE__->table('artist');
34 __PACKAGE__->add_columns(qw/ artistid name /);
35 __PACKAGE__->set_primary_key('artistid');
36 __PACKAGE__->has_many(cds => 'MyDB::Schema::Result::CD');
37
38 1;
39
40 # Create a query (view) based result source, in a result class
41 package MyDB::Schema::Result::Year2000CDs;
42
16ccb4fe 43 __PACKAGE__->load_components('Core');
44 __PACKAGE__->table_class('DBIx::Class::ResultSource::View');
45
46 __PACKAGE__->table('year2000cds');
47 __PACKAGE__->result_source_instance->is_virtual(1);
48 __PACKAGE__->result_source_instance->view_definition(
49 "SELECT cdid, artist, title FROM cd WHERE year ='2000'"
50 );
51
52
9c992ba1 53=head1 DESCRIPTION
54
16ccb4fe 55A ResultSource is an object that represents a source of data for querying.
56
57This class is a base class for various specialised types of result
58sources, for example L<DBIx::Class::ResultSource::Table>. Table is the
59default result source type, so one is created for you when defining a
60result class as described in the synopsis above.
61
62More specifically, the L<DBIx::Class::Core> component pulls in the
63L<DBIx::Class::ResultSourceProxy::Table> as a base class, which
64defines the L<table|DBIx::Class::ResultSourceProxy::Table/table>
65method. When called, C<table> creates and stores an instance of
66L<DBIx::Class::ResultSoure::Table>. Luckily, to use tables as result
67sources, you don't need to remember any of this.
68
69Result sources representing select queries, or views, can also be
70created, see L<DBIx::Class::ResultSource::View> for full details.
71
72=head2 Finding result source objects
73
74As mentioned above, a result source instance is created and stored for
75you when you define a L<Result Class|DBIx::Class::Manual::Glossary/Result Class>.
76
77You can retrieve the result source at runtime in the following ways:
78
79=over
80
81=item From a Schema object:
82
83 $schema->source($source_name);
84
85=item From a Row object:
9c992ba1 86
16ccb4fe 87 $row->result_source;
88
89=item From a ResultSet object:
90
91 $rs->result_source;
92
93=back
00be2e0b 94
9c992ba1 95=head1 METHODS
96
7eb4ecc8 97=pod
98
9c992ba1 99=cut
100
101sub new {
102 my ($class, $attrs) = @_;
103 $class = ref $class if ref $class;
04786a4c 104
6b051e14 105 my $new = bless { %{$attrs || {}} }, $class;
9c992ba1 106 $new->{resultset_class} ||= 'DBIx::Class::ResultSet';
5ac6a044 107 $new->{resultset_attributes} = { %{$new->{resultset_attributes} || {}} };
6da5894c 108 $new->{_ordered_columns} = [ @{$new->{_ordered_columns}||[]}];
109 $new->{_columns} = { %{$new->{_columns}||{}} };
110 $new->{_relationships} = { %{$new->{_relationships}||{}} };
9c992ba1 111 $new->{name} ||= "!!NAME NOT SET!!";
5afa2a15 112 $new->{_columns_info_loaded} ||= 0;
f89bb832 113 $new->{sqlt_deploy_callback} ||= "default_sqlt_deploy_hook";
9c992ba1 114 return $new;
115}
116
988bf309 117=pod
118
5ac6a044 119=head2 add_columns
120
391ccf38 121=over
122
123=item Arguments: @columns
124
125=item Return value: The ResultSource object
126
127=back
128
843f6bc1 129 $source->add_columns(qw/col1 col2 col3/);
5ac6a044 130
843f6bc1 131 $source->add_columns('col1' => \%col1_info, 'col2' => \%col2_info, ...);
5ac6a044 132
16ccb4fe 133Adds columns to the result source. If supplied colname => hashref
134pairs, uses the hashref as the L</column_info> for that column. Repeated
135calls of this method will add more columns, not replace them.
5ac6a044 136
5d9d9e87 137The column names given will be created as accessor methods on your
7e51afbf 138L<DBIx::Class::Row> objects. You can change the name of the accessor
5d9d9e87 139by supplying an L</accessor> in the column_info hash.
140
2053ab2a 141The contents of the column_info are not set in stone. The following
142keys are currently recognised/used by DBIx::Class:
988bf309 143
144=over 4
145
75d07914 146=item accessor
988bf309 147
16ccb4fe 148 { accessor => '_name' }
149
150 # example use, replace standard accessor with one of your own:
151 sub name {
152 my ($self, $value) = @_;
153
154 die "Name cannot contain digits!" if($value =~ /\d/);
155 $self->_name($value);
156
157 return $self->_name();
158 }
159
5d9d9e87 160Use this to set the name of the accessor method for this column. If unset,
988bf309 161the name of the column will be used.
162
163=item data_type
164
16ccb4fe 165 { data_type => 'integer' }
166
167This contains the column type. It is automatically filled if you use the
168L<SQL::Translator::Producer::DBIx::Class::File> producer, or the
169L<DBIx::Class::Schema::Loader> module.
988bf309 170
2053ab2a 171Currently there is no standard set of values for the data_type. Use
172whatever your database supports.
988bf309 173
174=item size
175
16ccb4fe 176 { size => 20 }
177
988bf309 178The length of your column, if it is a column type that can have a size
16ccb4fe 179restriction. This is currently only used to create tables from your
180schema, see L<DBIx::Class::Schema/deploy>.
988bf309 181
182=item is_nullable
183
16ccb4fe 184 { is_nullable => 1 }
185
186Set this to a true value for a columns that is allowed to contain NULL
187values, default is false. This is currently only used to create tables
188from your schema, see L<DBIx::Class::Schema/deploy>.
988bf309 189
190=item is_auto_increment
191
16ccb4fe 192 { is_auto_increment => 1 }
193
2053ab2a 194Set this to a true value for a column whose value is somehow
16ccb4fe 195automatically set, defaults to false. This is used to determine which
196columns to empty when cloning objects using
197L<DBIx::Class::Row/copy>. It is also used by
d7be2784 198L<DBIx::Class::Schema/deploy>.
988bf309 199
26a29815 200=item is_numeric
201
16ccb4fe 202 { is_numeric => 1 }
203
26a29815 204Set this to a true or false value (not C<undef>) to explicitly specify
205if this column contains numeric data. This controls how set_column
206decides whether to consider a column dirty after an update: if
0bad1823 207C<is_numeric> is true a numeric comparison C<< != >> will take place
26a29815 208instead of the usual C<eq>
209
210If not specified the storage class will attempt to figure this out on
211first access to the column, based on the column C<data_type>. The
212result will be cached in this attribute.
213
988bf309 214=item is_foreign_key
215
16ccb4fe 216 { is_foreign_key => 1 }
217
2053ab2a 218Set this to a true value for a column that contains a key from a
16ccb4fe 219foreign table, defaults to false. This is currently only used to
220create tables from your schema, see L<DBIx::Class::Schema/deploy>.
988bf309 221
222=item default_value
223
16ccb4fe 224 { default_value => \'now()' }
225
226Set this to the default value which will be inserted into a column by
227the database. Can contain either a value or a function (use a
4858fea7 228reference to a scalar e.g. C<\'now()'> if you want a function). This
16ccb4fe 229is currently only used to create tables from your schema, see
230L<DBIx::Class::Schema/deploy>.
988bf309 231
a4fcda00 232See the note on L<DBIx::Class::Row/new> for more information about possible
233issues related to db-side default values.
234
988bf309 235=item sequence
236
16ccb4fe 237 { sequence => 'my_table_seq' }
238
2053ab2a 239Set this on a primary key column to the name of the sequence used to
240generate a new key value. If not specified, L<DBIx::Class::PK::Auto>
241will attempt to retrieve the name of the sequence from the database
242automatically.
988bf309 243
838ef78d 244=item auto_nextval
245
ca791b95 246Set this to a true value for a column whose value is retrieved automatically
247from a sequence or function (if supported by your Storage driver.) For a
248sequence, if you do not use a trigger to get the nextval, you have to set the
249L</sequence> value as well.
250
251Also set this for MSSQL columns with the 'uniqueidentifier'
252L<DBIx::Class::ResultSource/data_type> whose values you want to automatically
253generate using C<NEWID()>, unless they are a primary key in which case this will
254be done anyway.
838ef78d 255
190615a7 256=item extra
d7be2784 257
258This is used by L<DBIx::Class::Schema/deploy> and L<SQL::Translator>
190615a7 259to add extra non-generic data to the column. For example: C<< extra
d7be2784 260=> { unsigned => 1} >> is used by the MySQL producer to set an integer
261column to unsigned. For more details, see
262L<SQL::Translator::Producer::MySQL>.
263
988bf309 264=back
265
5ac6a044 266=head2 add_column
267
391ccf38 268=over
269
16ccb4fe 270=item Arguments: $colname, \%columninfo?
391ccf38 271
272=item Return value: 1/0 (true/false)
273
274=back
275
16ccb4fe 276 $source->add_column('col' => \%info);
5ac6a044 277
391ccf38 278Add a single column and optional column info. Uses the same column
279info keys as L</add_columns>.
5ac6a044 280
281=cut
282
9c992ba1 283sub add_columns {
284 my ($self, @cols) = @_;
8e04bf91 285 $self->_ordered_columns(\@cols) unless $self->_ordered_columns;
002a359a 286
20518cb4 287 my @added;
288 my $columns = $self->_columns;
9c992ba1 289 while (my $col = shift @cols) {
8e04bf91 290 # If next entry is { ... } use that for the column info, if not
291 # use an empty hashref
30126ac7 292 my $column_info = ref $cols[0] ? shift(@cols) : {};
20518cb4 293 push(@added, $col) unless exists $columns->{$col};
20518cb4 294 $columns->{$col} = $column_info;
9c992ba1 295 }
20518cb4 296 push @{ $self->_ordered_columns }, @added;
30126ac7 297 return $self;
9c992ba1 298}
299
b25e9fa0 300sub add_column { shift->add_columns(@_); } # DO NOT CHANGE THIS TO GLOB
9c992ba1 301
3842b955 302=head2 has_column
303
391ccf38 304=over
305
306=item Arguments: $colname
307
308=item Return value: 1/0 (true/false)
309
310=back
311
843f6bc1 312 if ($source->has_column($colname)) { ... }
988bf309 313
2053ab2a 314Returns true if the source has a column of this name, false otherwise.
988bf309 315
316=cut
9c992ba1 317
318sub has_column {
319 my ($self, $column) = @_;
320 return exists $self->_columns->{$column};
321}
322
87c4e602 323=head2 column_info
9c992ba1 324
391ccf38 325=over
326
327=item Arguments: $colname
328
329=item Return value: Hashref of info
330
331=back
332
843f6bc1 333 my $info = $source->column_info($col);
9c992ba1 334
391ccf38 335Returns the column metadata hashref for a column, as originally passed
16ccb4fe 336to L</add_columns>. See L</add_columns> above for information on the
337contents of the hashref.
9c992ba1 338
988bf309 339=cut
9c992ba1 340
341sub column_info {
342 my ($self, $column) = @_;
75d07914 343 $self->throw_exception("No such column $column")
701da8c4 344 unless exists $self->_columns->{$column};
5afa2a15 345 #warn $self->{_columns_info_loaded}, "\n";
75d07914 346 if ( ! $self->_columns->{$column}{data_type}
6eda9bcf 347 and $self->column_info_from_storage
75d07914 348 and ! $self->{_columns_info_loaded}
8e04bf91 349 and $self->schema and $self->storage )
350 {
351 $self->{_columns_info_loaded}++;
d51f93c8 352 my $info = {};
353 my $lc_info = {};
75d07914 354 # eval for the case of storage without table
955f1590 355 eval { $info = $self->storage->columns_info_for( $self->from ) };
8e04bf91 356 unless ($@) {
0b88a5bb 357 for my $realcol ( keys %{$info} ) {
358 $lc_info->{lc $realcol} = $info->{$realcol};
359 }
8e04bf91 360 foreach my $col ( keys %{$self->_columns} ) {
d51f93c8 361 $self->_columns->{$col} = {
362 %{ $self->_columns->{$col} },
363 %{ $info->{$col} || $lc_info->{lc $col} || {} }
364 };
a953d8d9 365 }
8e04bf91 366 }
a953d8d9 367 }
9c992ba1 368 return $self->_columns->{$column};
369}
370
371=head2 columns
372
391ccf38 373=over
374
375=item Arguments: None
376
377=item Return value: Ordered list of column names
378
379=back
380
381 my @column_names = $source->columns;
20518cb4 382
391ccf38 383Returns all column names in the order they were declared to L</add_columns>.
87f0da6a 384
385=cut
9c992ba1 386
387sub columns {
8e04bf91 388 my $self = shift;
aa1088bf 389 $self->throw_exception(
390 "columns() is a read-only accessor, did you mean add_columns()?"
391 ) if (@_ > 1);
701da8c4 392 return @{$self->{_ordered_columns}||[]};
571dced3 393}
394
002a359a 395=head2 remove_columns
396
391ccf38 397=over
002a359a 398
391ccf38 399=item Arguments: @colnames
400
401=item Return value: undefined
402
403=back
404
405 $source->remove_columns(qw/col1 col2 col3/);
406
407Removes the given list of columns by name, from the result source.
408
409B<Warning>: Removing a column that is also used in the sources primary
410key, or in one of the sources unique constraints, B<will> result in a
411broken result source.
002a359a 412
413=head2 remove_column
414
391ccf38 415=over
416
417=item Arguments: $colname
418
419=item Return value: undefined
420
421=back
002a359a 422
391ccf38 423 $source->remove_column('col');
424
425Remove a single column by name from the result source, similar to
426L</remove_columns>.
427
428B<Warning>: Removing a column that is also used in the sources primary
429key, or in one of the sources unique constraints, B<will> result in a
430broken result source.
002a359a 431
432=cut
433
434sub remove_columns {
4738027b 435 my ($self, @to_remove) = @_;
002a359a 436
4738027b 437 my $columns = $self->_columns
438 or return;
002a359a 439
4738027b 440 my %to_remove;
441 for (@to_remove) {
a918d901 442 delete $columns->{$_};
4738027b 443 ++$to_remove{$_};
444 }
002a359a 445
4738027b 446 $self->_ordered_columns([ grep { not $to_remove{$_} } @{$self->_ordered_columns} ]);
002a359a 447}
448
b25e9fa0 449sub remove_column { shift->remove_columns(@_); } # DO NOT CHANGE THIS TO GLOB
002a359a 450
87c4e602 451=head2 set_primary_key
452
27f01d1f 453=over 4
454
ebc77b53 455=item Arguments: @cols
27f01d1f 456
391ccf38 457=item Return value: undefined
458
27f01d1f 459=back
87f0da6a 460
16ccb4fe 461Defines one or more columns as primary key for this source. Must be
391ccf38 462called after L</add_columns>.
87f0da6a 463
391ccf38 464Additionally, defines a L<unique constraint|add_unique_constraint>
465named C<primary>.
87f0da6a 466
988bf309 467The primary key columns are used by L<DBIx::Class::PK::Auto> to
16ccb4fe 468retrieve automatically created values from the database. They are also
469used as default joining columns when specifying relationships, see
470L<DBIx::Class::Relationship>.
988bf309 471
87f0da6a 472=cut
9c992ba1 473
474sub set_primary_key {
475 my ($self, @cols) = @_;
476 # check if primary key columns are valid columns
8e04bf91 477 foreach my $col (@cols) {
478 $self->throw_exception("No such column $col on table " . $self->name)
479 unless $self->has_column($col);
9c992ba1 480 }
481 $self->_primaries(\@cols);
87f0da6a 482
483 $self->add_unique_constraint(primary => \@cols);
9c992ba1 484}
485
87f0da6a 486=head2 primary_columns
487
391ccf38 488=over 4
489
490=item Arguments: None
491
492=item Return value: Ordered list of primary column names
493
494=back
495
496Read-only accessor which returns the list of primary keys, supplied by
497L</set_primary_key>.
30126ac7 498
87f0da6a 499=cut
9c992ba1 500
501sub primary_columns {
502 return @{shift->_primaries||[]};
503}
504
87f0da6a 505=head2 add_unique_constraint
506
391ccf38 507=over 4
508
16ccb4fe 509=item Arguments: $name?, \@colnames
391ccf38 510
511=item Return value: undefined
512
513=back
514
87f0da6a 515Declare a unique constraint on this source. Call once for each unique
58b5bb8c 516constraint.
27f01d1f 517
518 # For UNIQUE (column1, column2)
519 __PACKAGE__->add_unique_constraint(
520 constraint_name => [ qw/column1 column2/ ],
521 );
87f0da6a 522
368a5228 523Alternatively, you can specify only the columns:
524
525 __PACKAGE__->add_unique_constraint([ qw/column1 column2/ ]);
526
16ccb4fe 527This will result in a unique constraint named
528C<table_column1_column2>, where C<table> is replaced with the table
529name.
368a5228 530
16ccb4fe 531Unique constraints are used, for example, when you pass the constraint
532name as the C<key> attribute to L<DBIx::Class::ResultSet/find>. Then
533only columns in the constraint are searched.
58b5bb8c 534
391ccf38 535Throws an error if any of the given column names do not yet exist on
536the result source.
537
87f0da6a 538=cut
539
540sub add_unique_constraint {
368a5228 541 my $self = shift;
542 my $cols = pop @_;
543 my $name = shift;
544
545 $name ||= $self->name_unique_constraint($cols);
87f0da6a 546
8e04bf91 547 foreach my $col (@$cols) {
548 $self->throw_exception("No such column $col on table " . $self->name)
549 unless $self->has_column($col);
87f0da6a 550 }
551
552 my %unique_constraints = $self->unique_constraints;
553 $unique_constraints{$name} = $cols;
554 $self->_unique_constraints(\%unique_constraints);
555}
556
d9c74322 557=head2 name_unique_constraint
368a5228 558
391ccf38 559=over 4
560
561=item Arguments: @colnames
562
563=item Return value: Constraint name
564
565=back
566
567 $source->table('mytable');
568 $source->name_unique_constraint('col1', 'col2');
569 # returns
570 'mytable_col1_col2'
571
572Return a name for a unique constraint containing the specified
573columns. The name is created by joining the table name and each column
574name, using an underscore character.
368a5228 575
576For example, a constraint on a table named C<cd> containing the columns
577C<artist> and C<title> would result in a constraint name of C<cd_artist_title>.
578
391ccf38 579This is used by L</add_unique_constraint> if you do not specify the
580optional constraint name.
581
368a5228 582=cut
583
584sub name_unique_constraint {
585 my ($self, $cols) = @_;
586
3e6c1131 587 my $name = $self->name;
4678e9da 588 $name = $$name if (ref $name eq 'SCALAR');
3e6c1131 589
590 return join '_', $name, @$cols;
368a5228 591}
592
87f0da6a 593=head2 unique_constraints
594
391ccf38 595=over 4
596
597=item Arguments: None
598
599=item Return value: Hash of unique constraint data
600
601=back
602
603 $source->unique_constraints();
604
16ccb4fe 605Read-only accessor which returns a hash of unique constraints on this
606source.
391ccf38 607
608The hash is keyed by constraint name, and contains an arrayref of
609column names as values.
87f0da6a 610
611=cut
612
613sub unique_constraints {
614 return %{shift->_unique_constraints||{}};
615}
616
e6a0e17c 617=head2 unique_constraint_names
618
391ccf38 619=over 4
620
621=item Arguments: None
622
623=item Return value: Unique constraint names
624
625=back
626
627 $source->unique_constraint_names();
628
e6a0e17c 629Returns the list of unique constraint names defined on this source.
630
631=cut
632
633sub unique_constraint_names {
634 my ($self) = @_;
635
636 my %unique_constraints = $self->unique_constraints;
637
638 return keys %unique_constraints;
639}
640
641=head2 unique_constraint_columns
642
391ccf38 643=over 4
644
645=item Arguments: $constraintname
646
647=item Return value: List of constraint columns
648
649=back
650
651 $source->unique_constraint_columns('myconstraint');
652
e6a0e17c 653Returns the list of columns that make up the specified unique constraint.
654
655=cut
656
657sub unique_constraint_columns {
658 my ($self, $constraint_name) = @_;
659
660 my %unique_constraints = $self->unique_constraints;
661
662 $self->throw_exception(
663 "Unknown unique constraint $constraint_name on '" . $self->name . "'"
664 ) unless exists $unique_constraints{$constraint_name};
665
666 return @{ $unique_constraints{$constraint_name} };
667}
668
880c075b 669=head2 sqlt_deploy_callback
670
671=over
672
673=item Arguments: $callback
674
675=back
676
677 __PACKAGE__->sqlt_deploy_callback('mycallbackmethod');
678
679An accessor to set a callback to be called during deployment of
680the schema via L<DBIx::Class::Schema/create_ddl_dir> or
681L<DBIx::Class::Schema/deploy>.
682
683The callback can be set as either a code reference or the name of a
684method in the current result class.
685
686If not set, the L</default_sqlt_deploy_hook> is called.
687
688Your callback will be passed the $source object representing the
689ResultSource instance being deployed, and the
690L<SQL::Translator::Schema::Table> object being created from it. The
691callback can be used to manipulate the table object or add your own
692customised indexes. If you need to manipulate a non-table object, use
693the L<DBIx::Class::Schema/sqlt_deploy_hook>.
694
695See L<DBIx::Class::Manual::Cookbook/Adding Indexes And Functions To
696Your SQL> for examples.
697
698This sqlt deployment callback can only be used to manipulate
699SQL::Translator objects as they get turned into SQL. To execute
700post-deploy statements which SQL::Translator does not currently
701handle, override L<DBIx::Class::Schema/deploy> in your Schema class
702and call L<dbh_do|DBIx::Class::Storage::DBI/dbh_do>.
703
704=head2 default_sqlt_deploy_hook
705
706=over
707
708=item Arguments: $source, $sqlt_table
709
710=item Return value: undefined
711
712=back
713
714This is the sensible default for L</sqlt_deploy_callback>.
715
716If a method named C<sqlt_deploy_hook> exists in your Result class, it
717will be called and passed the current C<$source> and the
718C<$sqlt_table> being deployed.
719
720=cut
721
722sub default_sqlt_deploy_hook {
723 my $self = shift;
724
725 my $class = $self->result_class;
726
727 if ($class and $class->can('sqlt_deploy_hook')) {
728 $class->sqlt_deploy_hook(@_);
729 }
730}
731
732sub _invoke_sqlt_deploy_hook {
733 my $self = shift;
734 if ( my $hook = $self->sqlt_deploy_callback) {
735 $self->$hook(@_);
736 }
737}
738
843f6bc1 739=head2 resultset
740
741=over 4
742
743=item Arguments: None
744
745=item Return value: $resultset
746
747=back
748
749Returns a resultset for the given source. This will initially be created
750on demand by calling
751
752 $self->resultset_class->new($self, $self->resultset_attributes)
753
754but is cached from then on unless resultset_class changes.
755
756=head2 resultset_class
757
758=over 4
759
760=item Arguments: $classname
761
762=item Return value: $classname
763
764=back
765
16ccb4fe 766 package My::Schema::ResultSet::Artist;
843f6bc1 767 use base 'DBIx::Class::ResultSet';
768 ...
769
16ccb4fe 770 # In the result class
771 __PACKAGE__->resultset_class('My::Schema::ResultSet::Artist');
772
773 # Or in code
774 $source->resultset_class('My::Schema::ResultSet::Artist');
843f6bc1 775
7e51afbf 776Set the class of the resultset. This is useful if you want to create your
843f6bc1 777own resultset methods. Create your own class derived from
778L<DBIx::Class::ResultSet>, and set it here. If called with no arguments,
779this method returns the name of the existing resultset class, if one
780exists.
781
782=head2 resultset_attributes
783
784=over 4
785
786=item Arguments: \%attrs
787
788=item Return value: \%attrs
789
790=back
791
16ccb4fe 792 # In the result class
793 __PACKAGE__->resultset_attributes({ order_by => [ 'id' ] });
794
795 # Or in code
843f6bc1 796 $source->resultset_attributes({ order_by => [ 'id' ] });
797
798Store a collection of resultset attributes, that will be set on every
799L<DBIx::Class::ResultSet> produced from this result source. For a full
800list see L<DBIx::Class::ResultSet/ATTRIBUTES>.
801
802=cut
803
804sub resultset {
805 my $self = shift;
806 $self->throw_exception(
807 'resultset does not take any arguments. If you want another resultset, '.
808 'call it on the schema instead.'
809 ) if scalar @_;
810
811 return $self->resultset_class->new(
812 $self,
813 {
814 %{$self->{resultset_attributes}},
815 %{$self->schema->default_resultset_attributes}
816 },
817 );
818}
819
820=head2 source_name
821
822=over 4
823
824=item Arguments: $source_name
825
826=item Result value: $source_name
827
828=back
829
830Set an alternate name for the result source when it is loaded into a schema.
831This is useful if you want to refer to a result source by a name other than
832its class name.
833
834 package ArchivedBooks;
835 use base qw/DBIx::Class/;
836 __PACKAGE__->table('books_archive');
837 __PACKAGE__->source_name('Books');
838
839 # from your schema...
840 $schema->resultset('Books')->find(1);
841
9c992ba1 842=head2 from
843
391ccf38 844=over 4
845
846=item Arguments: None
847
848=item Return value: FROM clause
849
850=back
851
852 my $from_clause = $source->from();
853
9c992ba1 854Returns an expression of the source to be supplied to storage to specify
2053ab2a 855retrieval from this source. In the case of a database, the required FROM
856clause contents.
9c992ba1 857
f9b7bd6e 858=head2 schema
859
391ccf38 860=over 4
861
862=item Arguments: None
863
864=item Return value: A schema object
865
866=back
867
868 my $schema = $source->schema();
869
f9b7bd6e 870Returns the L<DBIx::Class::Schema> object that this result source
391ccf38 871belongs to.
9c992ba1 872
873=head2 storage
874
391ccf38 875=over 4
876
877=item Arguments: None
878
879=item Return value: A Storage object
880
881=back
882
883 $source->storage->debug(1);
884
75d07914 885Returns the storage handle for the current schema.
988bf309 886
887See also: L<DBIx::Class::Storage>
9c992ba1 888
889=cut
890
891sub storage { shift->schema->storage; }
892
8452e496 893=head2 add_relationship
894
391ccf38 895=over 4
896
897=item Arguments: $relname, $related_source_name, \%cond, [ \%attrs ]
898
899=item Return value: 1/true if it succeeded
900
901=back
902
8452e496 903 $source->add_relationship('relname', 'related_source', $cond, $attrs);
904
391ccf38 905L<DBIx::Class::Relationship> describes a series of methods which
906create pre-defined useful types of relationships. Look there first
907before using this method directly.
908
24d67825 909The relationship name can be arbitrary, but must be unique for each
910relationship attached to this result source. 'related_source' should
911be the name with which the related result source was registered with
912the current schema. For example:
8452e496 913
24d67825 914 $schema->source('Book')->add_relationship('reviews', 'Review', {
915 'foreign.book_id' => 'self.id',
916 });
917
2053ab2a 918The condition C<$cond> needs to be an L<SQL::Abstract>-style
24d67825 919representation of the join between the tables. For example, if you're
391ccf38 920creating a relation from Author to Book,
988bf309 921
922 { 'foreign.author_id' => 'self.id' }
923
924will result in the JOIN clause
925
926 author me JOIN book foreign ON foreign.author_id = me.id
927
8452e496 928You can specify as many foreign => self mappings as necessary.
929
988bf309 930Valid attributes are as follows:
931
932=over 4
933
934=item join_type
935
936Explicitly specifies the type of join to use in the relationship. Any
937SQL join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in
938the SQL command immediately before C<JOIN>.
939
940=item proxy
941
24d67825 942An arrayref containing a list of accessors in the foreign class to proxy in
943the main class. If, for example, you do the following:
002a359a 944
24d67825 945 CD->might_have(liner_notes => 'LinerNotes', undef, {
946 proxy => [ qw/notes/ ],
947 });
002a359a 948
24d67825 949Then, assuming LinerNotes has an accessor named notes, you can do:
988bf309 950
24d67825 951 my $cd = CD->find(1);
2053ab2a 952 # set notes -- LinerNotes object is created if it doesn't exist
953 $cd->notes('Notes go here');
988bf309 954
955=item accessor
956
957Specifies the type of accessor that should be created for the
75d07914 958relationship. Valid values are C<single> (for when there is only a single
959related object), C<multi> (when there can be many), and C<filter> (for
960when there is a single related object, but you also want the relationship
961accessor to double as a column accessor). For C<multi> accessors, an
962add_to_* method is also created, which calls C<create_related> for the
988bf309 963relationship.
964
8452e496 965=back
966
391ccf38 967Throws an exception if the condition is improperly supplied, or cannot
6d0ee587 968be resolved.
391ccf38 969
8452e496 970=cut
971
972sub add_relationship {
973 my ($self, $rel, $f_source_name, $cond, $attrs) = @_;
27f01d1f 974 $self->throw_exception("Can't create relationship without join condition")
975 unless $cond;
8452e496 976 $attrs ||= {};
87772e46 977
eba322a7 978 # Check foreign and self are right in cond
979 if ( (ref $cond ||'') eq 'HASH') {
980 for (keys %$cond) {
981 $self->throw_exception("Keys of condition should be of form 'foreign.col', not '$_'")
982 if /\./ && !/^foreign\./;
983 }
984 }
985
8452e496 986 my %rels = %{ $self->_relationships };
987 $rels{$rel} = { class => $f_source_name,
87772e46 988 source => $f_source_name,
8452e496 989 cond => $cond,
990 attrs => $attrs };
991 $self->_relationships(\%rels);
992
30126ac7 993 return $self;
87772e46 994
953a18ef 995 # XXX disabled. doesn't work properly currently. skip in tests.
996
8452e496 997 my $f_source = $self->schema->source($f_source_name);
998 unless ($f_source) {
c037c03a 999 $self->ensure_class_loaded($f_source_name);
8452e496 1000 $f_source = $f_source_name->result_source;
87772e46 1001 #my $s_class = ref($self->schema);
1002 #$f_source_name =~ m/^${s_class}::(.*)$/;
1003 #$self->schema->register_class(($1 || $f_source_name), $f_source_name);
1004 #$f_source = $self->schema->source($f_source_name);
8452e496 1005 }
1006 return unless $f_source; # Can't test rel without f_source
1007
88a66388 1008 eval { $self->_resolve_join($rel, 'me', {}, []) };
8452e496 1009
1010 if ($@) { # If the resolve failed, back out and re-throw the error
75d07914 1011 delete $rels{$rel}; #
8452e496 1012 $self->_relationships(\%rels);
701da8c4 1013 $self->throw_exception("Error creating relationship $rel: $@");
8452e496 1014 }
1015 1;
1016}
1017
87c4e602 1018=head2 relationships
8452e496 1019
391ccf38 1020=over 4
1021
1022=item Arguments: None
1023
1024=item Return value: List of relationship names
1025
1026=back
1027
1028 my @relnames = $source->relationships();
1029
2053ab2a 1030Returns all relationship names for this source.
8452e496 1031
1032=cut
1033
1034sub relationships {
1035 return keys %{shift->_relationships};
1036}
1037
87c4e602 1038=head2 relationship_info
1039
27f01d1f 1040=over 4
1041
ebc77b53 1042=item Arguments: $relname
27f01d1f 1043
391ccf38 1044=item Return value: Hashref of relation data,
1045
27f01d1f 1046=back
8452e496 1047
2053ab2a 1048Returns a hash of relationship information for the specified relationship
391ccf38 1049name. The keys/values are as specified for L</add_relationship>.
8452e496 1050
1051=cut
1052
1053sub relationship_info {
1054 my ($self, $rel) = @_;
1055 return $self->_relationships->{$rel};
75d07914 1056}
8452e496 1057
87c4e602 1058=head2 has_relationship
1059
27f01d1f 1060=over 4
1061
ebc77b53 1062=item Arguments: $rel
27f01d1f 1063
391ccf38 1064=item Return value: 1/0 (true/false)
1065
27f01d1f 1066=back
953a18ef 1067
2053ab2a 1068Returns true if the source has a relationship of this name, false otherwise.
988bf309 1069
1070=cut
953a18ef 1071
1072sub has_relationship {
1073 my ($self, $rel) = @_;
1074 return exists $self->_relationships->{$rel};
1075}
1076
de60a93d 1077=head2 reverse_relationship_info
1078
1079=over 4
1080
1081=item Arguments: $relname
1082
391ccf38 1083=item Return value: Hashref of relationship data
1084
de60a93d 1085=back
1086
391ccf38 1087Looks through all the relationships on the source this relationship
1088points to, looking for one whose condition is the reverse of the
1089condition on this relationship.
1090
1091A common use of this is to find the name of the C<belongs_to> relation
1092opposing a C<has_many> relation. For definition of these look in
1093L<DBIx::Class::Relationship>.
1094
1095The returned hashref is keyed by the name of the opposing
faaba25f 1096relationship, and contains its data in the same manner as
391ccf38 1097L</relationship_info>.
de60a93d 1098
1099=cut
1100
1101sub reverse_relationship_info {
1102 my ($self, $rel) = @_;
1103 my $rel_info = $self->relationship_info($rel);
1104 my $ret = {};
1105
1106 return $ret unless ((ref $rel_info->{cond}) eq 'HASH');
1107
1108 my @cond = keys(%{$rel_info->{cond}});
1109 my @refkeys = map {/^\w+\.(\w+)$/} @cond;
1110 my @keys = map {$rel_info->{cond}->{$_} =~ /^\w+\.(\w+)$/} @cond;
bab77431 1111
de60a93d 1112 # Get the related result source for this relationship
1113 my $othertable = $self->related_source($rel);
1114
1115 # Get all the relationships for that source that related to this source
1116 # whose foreign column set are our self columns on $rel and whose self
bab77431 1117 # columns are our foreign columns on $rel.
de60a93d 1118 my @otherrels = $othertable->relationships();
1119 my $otherrelationship;
1120 foreach my $otherrel (@otherrels) {
1121 my $otherrel_info = $othertable->relationship_info($otherrel);
1122
1123 my $back = $othertable->related_source($otherrel);
f3fb2641 1124 next unless $back->source_name eq $self->source_name;
de60a93d 1125
1126 my @othertestconds;
1127
1128 if (ref $otherrel_info->{cond} eq 'HASH') {
1129 @othertestconds = ($otherrel_info->{cond});
1130 }
1131 elsif (ref $otherrel_info->{cond} eq 'ARRAY') {
1132 @othertestconds = @{$otherrel_info->{cond}};
1133 }
1134 else {
1135 next;
1136 }
1137
1138 foreach my $othercond (@othertestconds) {
1139 my @other_cond = keys(%$othercond);
1140 my @other_refkeys = map {/^\w+\.(\w+)$/} @other_cond;
1141 my @other_keys = map {$othercond->{$_} =~ /^\w+\.(\w+)$/} @other_cond;
6d0ee587 1142 next if (!$self->_compare_relationship_keys(\@refkeys, \@other_keys) ||
1143 !$self->_compare_relationship_keys(\@other_refkeys, \@keys));
de60a93d 1144 $ret->{$otherrel} = $otherrel_info;
1145 }
1146 }
1147 return $ret;
1148}
1149
de60a93d 1150sub compare_relationship_keys {
6d0ee587 1151 carp 'compare_relationship_keys is a private method, stop calling it';
1152 my $self = shift;
1153 $self->_compare_relationship_keys (@_);
1154}
1155
1156# Returns true if both sets of keynames are the same, false otherwise.
1157sub _compare_relationship_keys {
de60a93d 1158 my ($self, $keys1, $keys2) = @_;
1159
1160 # Make sure every keys1 is in keys2
1161 my $found;
1162 foreach my $key (@$keys1) {
1163 $found = 0;
1164 foreach my $prim (@$keys2) {
1165 if ($prim eq $key) {
1166 $found = 1;
1167 last;
1168 }
1169 }
1170 last unless $found;
1171 }
1172
1173 # Make sure every key2 is in key1
1174 if ($found) {
1175 foreach my $prim (@$keys2) {
1176 $found = 0;
1177 foreach my $key (@$keys1) {
1178 if ($prim eq $key) {
1179 $found = 1;
1180 last;
1181 }
1182 }
1183 last unless $found;
1184 }
1185 }
1186
1187 return $found;
1188}
1189
8452e496 1190sub resolve_join {
6d0ee587 1191 carp 'resolve_join is a private method, stop calling it';
1192 my $self = shift;
1193 $self->_resolve_join (@_);
1194}
1195
1196# Returns the {from} structure used to express JOIN conditions
1197sub _resolve_join {
b230b4be 1198 my ($self, $join, $alias, $seen, $jpath, $force_left) = @_;
1979278e 1199
1200 # we need a supplied one, because we do in-place modifications, no returns
6d0ee587 1201 $self->throw_exception ('You must supply a seen hashref as the 3rd argument to _resolve_join')
88a66388 1202 unless ref $seen eq 'HASH';
1979278e 1203
88a66388 1204 $self->throw_exception ('You must supply a joinpath arrayref as the 4th argument to _resolve_join')
1205 unless ref $jpath eq 'ARRAY';
1206
1207 $jpath = [@$jpath];
1979278e 1208
87772e46 1209 if (ref $join eq 'ARRAY') {
caac1708 1210 return
1211 map {
88a66388 1212 $self->_resolve_join($_, $alias, $seen, $jpath, $force_left);
caac1708 1213 } @$join;
87772e46 1214 } elsif (ref $join eq 'HASH') {
489709af 1215 return
887ce227 1216 map {
1979278e 1217 my $as = ($seen->{$_} ? join ('_', $_, $seen->{$_} + 1) : $_); # the actual seen value will be incremented below
caac1708 1218 local $force_left->{force} = $force_left->{force};
24010dd8 1219 (
b230b4be 1220 $self->_resolve_join($_, $alias, $seen, [@$jpath], $force_left),
6d0ee587 1221 $self->related_source($_)->_resolve_join(
b230b4be 1222 $join->{$_}, $as, $seen, [@$jpath, $_], $force_left
24010dd8 1223 )
1224 );
887ce227 1225 } keys %$join;
87772e46 1226 } elsif (ref $join) {
701da8c4 1227 $self->throw_exception("No idea how to resolve join reftype ".ref $join);
87772e46 1228 } else {
1979278e 1229
096395af 1230 return() unless defined $join;
1231
489709af 1232 my $count = ++$seen->{$join};
489709af 1233 my $as = ($count > 1 ? "${join}_${count}" : $join);
1979278e 1234
3842b955 1235 my $rel_info = $self->relationship_info($join);
701da8c4 1236 $self->throw_exception("No such relationship ${join}") unless $rel_info;
24010dd8 1237 my $type;
b230b4be 1238 if ($force_left) {
24010dd8 1239 $type = 'left';
1240 } else {
1241 $type = $rel_info->{attrs}{join_type} || '';
b230b4be 1242 $force_left = 1 if lc($type) eq 'left';
24010dd8 1243 }
ba61fa2a 1244
1245 my $rel_src = $self->related_source($join);
1246 return [ { $as => $rel_src->from,
35ec0366 1247 -source_handle => $rel_src->handle,
1979278e 1248 -join_type => $type,
1249 -join_path => [@$jpath, $join],
ba61fa2a 1250 -alias => $as,
1979278e 1251 -relation_chain_depth => $seen->{-relation_chain_depth} || 0,
1252 },
6d0ee587 1253 $self->_resolve_condition($rel_info->{cond}, $as, $alias) ];
953a18ef 1254 }
1255}
1256
370f2ba2 1257sub pk_depends_on {
6d0ee587 1258 carp 'pk_depends_on is a private method, stop calling it';
1259 my $self = shift;
1260 $self->_pk_depends_on (@_);
1261}
1262
1263# Determines whether a relation is dependent on an object from this source
1264# having already been inserted. Takes the name of the relationship and a
1265# hashref of columns of the related object.
1266sub _pk_depends_on {
370f2ba2 1267 my ($self, $relname, $rel_data) = @_;
370f2ba2 1268
c39b48e5 1269 my $relinfo = $self->relationship_info($relname);
1270
1271 # don't assume things if the relationship direction is specified
1272 return $relinfo->{attrs}{is_foreign_key_constraint}
1273 if exists ($relinfo->{attrs}{is_foreign_key_constraint});
1274
1275 my $cond = $relinfo->{cond};
370f2ba2 1276 return 0 unless ref($cond) eq 'HASH';
1277
1278 # map { foreign.foo => 'self.bar' } to { bar => 'foo' }
370f2ba2 1279 my $keyhash = { map { my $x = $_; $x =~ s/.*\.//; $x; } reverse %$cond };
1280
1281 # assume anything that references our PK probably is dependent on us
1282 # rather than vice versa, unless the far side is (a) defined or (b)
1283 # auto-increment
370f2ba2 1284 my $rel_source = $self->related_source($relname);
1285
1286 foreach my $p ($self->primary_columns) {
1287 if (exists $keyhash->{$p}) {
1288 unless (defined($rel_data->{$keyhash->{$p}})
1289 || $rel_source->column_info($keyhash->{$p})
1290 ->{is_auto_increment}) {
1291 return 0;
1292 }
1293 }
1294 }
1295
1296 return 1;
1297}
1298
6d0ee587 1299sub resolve_condition {
1300 carp 'resolve_condition is a private method, stop calling it';
1301 my $self = shift;
1302 $self->_resolve_condition (@_);
1303}
953a18ef 1304
6d0ee587 1305# Resolves the passed condition to a concrete query fragment. If given an alias,
1306# returns a join condition; if given an object, inverts that object to produce
1307# a related conditional from that object.
8c368cf3 1308our $UNRESOLVABLE_CONDITION = \'1 = 0';
1309
6d0ee587 1310sub _resolve_condition {
489709af 1311 my ($self, $cond, $as, $for) = @_;
953a18ef 1312 if (ref $cond eq 'HASH') {
1313 my %ret;
bd054cb4 1314 foreach my $k (keys %{$cond}) {
1315 my $v = $cond->{$k};
953a18ef 1316 # XXX should probably check these are valid columns
27f01d1f 1317 $k =~ s/^foreign\.// ||
75d07914 1318 $self->throw_exception("Invalid rel cond key ${k}");
27f01d1f 1319 $v =~ s/^self\.// ||
75d07914 1320 $self->throw_exception("Invalid rel cond val ${v}");
953a18ef 1321 if (ref $for) { # Object
3842b955 1322 #warn "$self $k $for $v";
370f2ba2 1323 unless ($for->has_column_loaded($v)) {
1324 if ($for->in_storage) {
a4fcda00 1325 $self->throw_exception(
1326 "Column ${v} not loaded or not passed to new() prior to insert()"
1327 ." on ${for} trying to resolve relationship (maybe you forgot "
286fa9c5 1328 ."to call ->discard_changes to get defaults from the db)"
a4fcda00 1329 );
370f2ba2 1330 }
68f3b0dd 1331 return $UNRESOLVABLE_CONDITION;
370f2ba2 1332 }
1333 $ret{$k} = $for->get_column($v);
1334 #$ret{$k} = $for->get_column($v) if $for->has_column_loaded($v);
3842b955 1335 #warn %ret;
2c037e6b 1336 } elsif (!defined $for) { # undef, i.e. "no object"
1337 $ret{$k} = undef;
2ec8e594 1338 } elsif (ref $as eq 'HASH') { # reverse hashref
1339 $ret{$v} = $as->{$k};
fde6e28e 1340 } elsif (ref $as) { # reverse object
1341 $ret{$v} = $as->get_column($k);
2c037e6b 1342 } elsif (!defined $as) { # undef, i.e. "no reverse object"
1343 $ret{$v} = undef;
953a18ef 1344 } else {
489709af 1345 $ret{"${as}.${k}"} = "${for}.${v}";
953a18ef 1346 }
953a18ef 1347 }
1348 return \%ret;
5efe4c79 1349 } elsif (ref $cond eq 'ARRAY') {
6d0ee587 1350 return [ map { $self->_resolve_condition($_, $as, $for) } @$cond ];
953a18ef 1351 } else {
35c77aa3 1352 die("Can't handle condition $cond yet :(");
87772e46 1353 }
1354}
1355
3bb4eb8f 1356# Legacy code, needs to go entirely away (fully replaced by _resolve_prefetch)
6d0ee587 1357sub resolve_prefetch {
1358 carp 'resolve_prefetch is a private method, stop calling it';
3bb4eb8f 1359
1360 my ($self, $pre, $alias, $seen, $order, $collapse) = @_;
1361 $seen ||= {};
1362 if( ref $pre eq 'ARRAY' ) {
1363 return
1364 map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) }
1365 @$pre;
1366 }
1367 elsif( ref $pre eq 'HASH' ) {
1368 my @ret =
1369 map {
1370 $self->resolve_prefetch($_, $alias, $seen, $order, $collapse),
1371 $self->related_source($_)->resolve_prefetch(
1372 $pre->{$_}, "${alias}.$_", $seen, $order, $collapse)
1373 } keys %$pre;
1374 return @ret;
1375 }
1376 elsif( ref $pre ) {
1377 $self->throw_exception(
1378 "don't know how to resolve prefetch reftype ".ref($pre));
1379 }
1380 else {
1381 my $count = ++$seen->{$pre};
1382 my $as = ($count > 1 ? "${pre}_${count}" : $pre);
1383 my $rel_info = $self->relationship_info( $pre );
1384 $self->throw_exception( $self->name . " has no such relationship '$pre'" )
1385 unless $rel_info;
1386 my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
1387 my $rel_source = $self->related_source($pre);
1388
1389 if (exists $rel_info->{attrs}{accessor}
1390 && $rel_info->{attrs}{accessor} eq 'multi') {
1391 $self->throw_exception(
1392 "Can't prefetch has_many ${pre} (join cond too complex)")
1393 unless ref($rel_info->{cond}) eq 'HASH';
1394 my $dots = @{[$as_prefix =~ m/\./g]} + 1; # +1 to match the ".${as_prefix}"
27ffa6c0 1395
3bb4eb8f 1396 #my @col = map { (/^self\.(.+)$/ ? ("${as_prefix}.$1") : ()); }
1397 # values %{$rel_info->{cond}};
1398 $collapse->{".${as_prefix}${pre}"} = [ $rel_source->primary_columns ];
1399 # action at a distance. prepending the '.' allows simpler code
1400 # in ResultSet->_collapse_result
1401 my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
1402 keys %{$rel_info->{cond}};
1403 my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
1404 ? @{$rel_info->{attrs}{order_by}}
1405 : (defined $rel_info->{attrs}{order_by}
1406 ? ($rel_info->{attrs}{order_by})
1407 : ()));
1408 push(@$order, map { "${as}.$_" } (@key, @ord));
1409 }
1410
1411 return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
1412 $rel_source->columns;
1413 }
6d0ee587 1414}
988bf309 1415
6d0ee587 1416# Accepts one or more relationships for the current source and returns an
1417# array of column names for each of those relationships. Column names are
1418# prefixed relative to the current source, in accordance with where they appear
1419# in the supplied relationships. Needs an alias_map generated by
1420# $rs->_joinpath_aliases
b3e8ac9b 1421
6d0ee587 1422sub _resolve_prefetch {
1979278e 1423 my ($self, $pre, $alias, $alias_map, $order, $collapse, $pref_path) = @_;
1424 $pref_path ||= [];
1425
b3e8ac9b 1426 if( ref $pre eq 'ARRAY' ) {
0f66a01b 1427 return
6d0ee587 1428 map { $self->_resolve_prefetch( $_, $alias, $alias_map, $order, $collapse, [ @$pref_path ] ) }
0f66a01b 1429 @$pre;
b3e8ac9b 1430 }
1431 elsif( ref $pre eq 'HASH' ) {
1432 my @ret =
1433 map {
6d0ee587 1434 $self->_resolve_prefetch($_, $alias, $alias_map, $order, $collapse, [ @$pref_path ] ),
1435 $self->related_source($_)->_resolve_prefetch(
1979278e 1436 $pre->{$_}, "${alias}.$_", $alias_map, $order, $collapse, [ @$pref_path, $_] )
0f66a01b 1437 } keys %$pre;
b3e8ac9b 1438 return @ret;
1439 }
1440 elsif( ref $pre ) {
a86b1efe 1441 $self->throw_exception(
1442 "don't know how to resolve prefetch reftype ".ref($pre));
b3e8ac9b 1443 }
1444 else {
1979278e 1445 my $p = $alias_map;
1446 $p = $p->{$_} for (@$pref_path, $pre);
1447
1448 $self->throw_exception (
88a66388 1449 "Unable to resolve prefetch $pre - join alias map does not contain an entry for path: "
1979278e 1450 . join (' -> ', @$pref_path, $pre)
1451 ) if (ref $p->{-join_aliases} ne 'ARRAY' or not @{$p->{-join_aliases}} );
88a66388 1452
1979278e 1453 my $as = shift @{$p->{-join_aliases}};
1454
b3e8ac9b 1455 my $rel_info = $self->relationship_info( $pre );
a86b1efe 1456 $self->throw_exception( $self->name . " has no such relationship '$pre'" )
1457 unless $rel_info;
37f23589 1458 my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
a86b1efe 1459 my $rel_source = $self->related_source($pre);
0f66a01b 1460
1461 if (exists $rel_info->{attrs}{accessor}
1462 && $rel_info->{attrs}{accessor} eq 'multi') {
1463 $self->throw_exception(
1464 "Can't prefetch has_many ${pre} (join cond too complex)")
1465 unless ref($rel_info->{cond}) eq 'HASH';
cb136e67 1466 my $dots = @{[$as_prefix =~ m/\./g]} + 1; # +1 to match the ".${as_prefix}"
27ffa6c0 1467
b25e9fa0 1468 #my @col = map { (/^self\.(.+)$/ ? ("${as_prefix}.$1") : ()); }
1469 # values %{$rel_info->{cond}};
1470 $collapse->{".${as_prefix}${pre}"} = [ $rel_source->primary_columns ];
1471 # action at a distance. prepending the '.' allows simpler code
1472 # in ResultSet->_collapse_result
37f23589 1473 my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
0f66a01b 1474 keys %{$rel_info->{cond}};
5a5bec6c 1475 my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
1476 ? @{$rel_info->{attrs}{order_by}}
1477 : (defined $rel_info->{attrs}{order_by}
1478 ? ($rel_info->{attrs}{order_by})
1479 : ()));
1480 push(@$order, map { "${as}.$_" } (@key, @ord));
0f66a01b 1481 }
1482
489709af 1483 return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
a86b1efe 1484 $rel_source->columns;
b3e8ac9b 1485 }
1486}
953a18ef 1487
87c4e602 1488=head2 related_source
1489
27f01d1f 1490=over 4
1491
ebc77b53 1492=item Arguments: $relname
27f01d1f 1493
391ccf38 1494=item Return value: $source
1495
27f01d1f 1496=back
87772e46 1497
2053ab2a 1498Returns the result source object for the given relationship.
87772e46 1499
1500=cut
1501
1502sub related_source {
1503 my ($self, $rel) = @_;
aea52c85 1504 if( !$self->has_relationship( $rel ) ) {
701da8c4 1505 $self->throw_exception("No such relationship '$rel'");
aea52c85 1506 }
87772e46 1507 return $self->schema->source($self->relationship_info($rel)->{source});
8452e496 1508}
1509
77254782 1510=head2 related_class
1511
27f01d1f 1512=over 4
1513
ebc77b53 1514=item Arguments: $relname
27f01d1f 1515
391ccf38 1516=item Return value: $classname
1517
27f01d1f 1518=back
77254782 1519
2053ab2a 1520Returns the class name for objects in the given relationship.
77254782 1521
1522=cut
1523
1524sub related_class {
1525 my ($self, $rel) = @_;
1526 if( !$self->has_relationship( $rel ) ) {
1527 $self->throw_exception("No such relationship '$rel'");
1528 }
1529 return $self->schema->class($self->relationship_info($rel)->{source});
1530}
1531
aec3eff1 1532=head2 handle
1533
1534Obtain a new handle to this source. Returns an instance of a
1535L<DBIx::Class::ResultSourceHandle>.
1536
1537=cut
1538
1539sub handle {
1540 return new DBIx::Class::ResultSourceHandle({
1541 schema => $_[0]->schema,
3441fd57 1542 source_moniker => $_[0]->source_name
aec3eff1 1543 });
1544}
1545
701da8c4 1546=head2 throw_exception
1547
2053ab2a 1548See L<DBIx::Class::Schema/"throw_exception">.
701da8c4 1549
1550=cut
1551
1552sub throw_exception {
1553 my $self = shift;
75d07914 1554 if (defined $self->schema) {
701da8c4 1555 $self->schema->throw_exception(@_);
1556 } else {
1557 croak(@_);
1558 }
1559}
1560
843f6bc1 1561=head2 source_info
d2f3e87b 1562
843f6bc1 1563Stores a hashref of per-source metadata. No specific key names
1564have yet been standardized, the examples below are purely hypothetical
1565and don't actually accomplish anything on their own:
391ccf38 1566
843f6bc1 1567 __PACKAGE__->source_info({
1568 "_tablespace" => 'fast_disk_array_3',
1569 "_engine" => 'InnoDB',
1570 });
391ccf38 1571
843f6bc1 1572=head2 new
391ccf38 1573
843f6bc1 1574 $class->new();
391ccf38 1575
843f6bc1 1576 $class->new({attribute_name => value});
d2f3e87b 1577
843f6bc1 1578Creates a new ResultSource object. Not normally called directly by end users.
391ccf38 1579
843f6bc1 1580=head2 column_info_from_storage
1581
1582=over
1583
1584=item Arguments: 1/0 (default: 0)
1585
1586=item Return value: 1/0
1587
1588=back
1589
880c075b 1590 __PACKAGE__->column_info_from_storage(1);
1591
843f6bc1 1592Enables the on-demand automatic loading of the above column
1593metadata from storage as neccesary. This is *deprecated*, and
1594should not be used. It will be removed before 1.0.
1595
f89bb832 1596
9c992ba1 1597=head1 AUTHORS
1598
1599Matt S. Trout <mst@shadowcatsystems.co.uk>
1600
1601=head1 LICENSE
1602
1603You may distribute this code under the same terms as Perl itself.
1604
1605=cut
1606
b25e9fa0 16071;