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